一、响应数据和结果视图
1.1 返回值分类
1.1.1 字符串
controller
中的方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。- 物理路径为
/WEB-INF/pages/success.jsp
- 物理路径为
@RequestMapping("/testReturnString")
public String test01(){
System.out.println("测试成功");
return "success";
}
1.1.2 void
Servlet
原始API可以作为控制器中方法的参数转发
forward
@RequestMappint("/testReturnVoid") public void testReturnVoid(HttpServletRequest request, HttpServletResponse response){ request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response); }
重定向
@RequestMappint("/testReturnVoid") public void testReturnVoid(HttpServletRequest request, HttpServletResponse response){ response.sendRedirect("testReturnString"); }
响应json结果
@RequestMappint("/testReturnVoid") public void testReturnVoid(HttpServletRequest request, HttpServletResponse response){ response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("json串"); }
1.1.3 ModelAndView
ModelAndView是SpringMVC为我们提供的一个对象,也可作为控制器方法的返回值。
@RequestMapping("/testReturnModelAndView") public ModelAndView testReturnModelAndView() { ModelAndView mv = new ModelAndView(); mv.addObject("username", "张三"); mv.setViewName("success"); return mv; }
1.2 转发和重定向
1.2.1 forward转发
controller
方法在提供了String
类型的返回值之后,默认就是请求转发。返回值:
forward:url
,其中url
为实际视图的地址@RequestMapping("/testForward") public String testForward(){ System.out.println("转发"); return "forward:/WEB-INF/pages/success.jsp"; }
1.2.2 redirect重定向
- 返回值:
redirect:url
- 如果重定向到jsp页面,这个jsp页面不能写在
WEB-INF
目录中,不然是找不到的。
1.3 ResponseBody响应json数据
@ResponseBody
注解将Controller
方法返回的对象,通过HttpMessageConverter
接口转换为指定格式的数据,如json、xml等,并Response给客户端。需要导包:
jackson-annotations-2.9.0.jar
jackson-databind-2.9.0.jar
jackson-core-2.9.0.jar
代码示例
前端发送ajax异步请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>response</title> <script src="js/jquery.min.js"></script> <script> $(function () { $("#btn").click(function () { $.ajax({ url:"user/testAjax", contentType:"application/json;charset=UTF-8", //data:{"username":"tom", "password":"123", "age":23}, data:'{"username":"tom","password":"123","age":23}', dataType:"json", type:"post", success:function(data){ //服务器响应回来的数据显示 alert(data); alert(data.username); } }); }); }); </script> </head> <body> <button id="btn">发送ajax请求</button> </body> </html>
两种方式:
传的是json字符串
contentType:"application/json;charset=UTF-8", data:'{"username":"tom","password":"123","age":23}',
- 必须设置`contentType`
- data是字符串类型
2. 传的是表单数据类型
data:{"username":"tom", "password":"123", "age":23},
controller
代码接收的是json字符串
@RequestMapping("/testAjax") public @ResponseBody User testAjax(@RequestBody User user){ System.out.println("testAjax执行了"); System.out.println(user); user.setUsername("alex"); return user; }
- 形参内必须加上`@RequestBody`注解,因为解析的是字符串
2. 接收的是表单数据
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(User user){
System.out.println("testAjax执行了");
System.out.println(user);
user.setUsername("alex");
return user;
}
- 形参内没有`@RequestBody`注解
二、SpringMVC实现文件上传
2.1 文件上传的回顾
2.1.1 文件上传的必要前提
form表单的enctype取值必须是:
multipart/form-data
enctype
:表单请求正文的类型
method
一定要是post
- 提供一个文件选择域:
<input type="file">
2.1.2 借助第三方组件实现文件上传
commons-fileupload-1.3.1.jar
commons-io-2.4.jar
2.2 传统方式上传文件
2.2.1 导包
commons-fileupload-1.3.1.jar
commons-io-2.4.jar
2.2.2 前端jsp页面
<h2>传统方式文件上传</h2>
<form action="user/fileUpload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="file">
<input type="submit" value="上传文件">
</form>
2.2.3 编写控制器方法
/**
* 传统方式文件上传
* @param request
* @return
* @throws Exception
*/
@RequestMapping("/fileUpload")
public String fileUpload(HttpServletRequest request) throws Exception {
//设置上传位置
String path = request.getSession().getServletContext().getRealPath("/upload/");
//判断该路径是否存在
File file = new File(path);
if (!file.exists()) {
//如果不存在,创建文件夹
file.mkdirs();
}
//解析request对象,获取上传文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request
List<FileItem> items = upload.parseRequest(request);
//遍历
for (FileItem item : items) {
//判断当前item对象是否为上传文件项
if (item.isFormField()) {
//为普通表单项
} else {
//为上传文件项
//获得文件名
String filename = item.getName();
String uuid = UUID.randomUUID().toString().replace("-", "");
//使得上传文件名是唯一的
filename = uuid + "_" + filename;
item.write(new File(path, filename));
//删除临时文件
item.delete();
}
System.out.println(path);
}
return "success";
}
2.2.4 配置文件解析器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.ruki"></context:component-scan>
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
2.3 SpringMVC跨服务器上传文件
分服务器的目的:在实际开发中,会有很多处理不同功能的服务器,如
- 应用服务器:负责部署应用
- 数据库服务器:运行数据库
- 缓存和消息服务器:负责处理大并发访问的缓存和消息
- 文件服务器:负责存储用户上传文件的服务器。
2.3.1 准备两个tomcat服务器
- 其中一个服务器部署的web工程,专用来存放图片。(需要修改端口号)
对文件服务器的
web.xml
文件进行修改,允许读写操作!<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
2.3.2 导包
jersey-client-1.18.1.jar
jersey-core-1.18.1.jar
commons-fileupload-1.3.1.jar
commons-io-2.4.jar
2.3.3 编写控制器方法
@Controller("fileUploadController2")
public class FileUploadController2 {
public static final String FILESERVERURL = "http://localhost:9090/day06_spring_image/uploads/";
/**
* 文件上传,保存文件到不同服务器
*/
@RequestMapping("/fileUpload2")
public String testResponseJson(String picname,MultipartFile uploadFile) throws Exception{
//定义文件名
String fileName = "";
//1.获取原始文件名
String uploadFileName = uploadFile.getOriginalFilename();
//2.截取文件扩展名
String extendName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1, uploadFileName.length());
//3.把文件加上随机数,防止文件重复
String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase();
//4.判断是否输入了文件名
if(!StringUtils.isEmpty(picname)) {
fileName = uuid+"_"+picname+"."+extendName;
}else {
fileName = uuid+"_"+uploadFileName;
}
System.out.println(fileName);
//5.创建sun公司提供的jersey包中的Client对象
Client client = Client.create();
//6.指定上传文件的地址,该地址是web路径
WebResource resource = client.resource(FILESERVERURL+fileName);
//7.实现上传
String result = resource.put(String.class,uploadFile.getBytes());
System.out.println(result);
return "success";
}
}
2.3.4 前端jsp页面
<form action="fileUpload2" method="post" enctype="multipart/form-data">
名称:<input type="text" name="picname"/><br/>
图片:<input type="file" name="uploadFile"/><br/>
<input type="submit" value="上传"/>
</form>
2.3.5 配置文件解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
三、SpringMVC中的异常处理
3.1 异常处理流程
3.2 实现步骤
3.2.1 自定义异常
package com.ruki.exception;
public class SysException extends Exception {
private String message;
public SysException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
3.2.2 错误提示页面
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>error</title>
</head>
<body>
${errorMsg}
</body>
</html>
3.2.3 自定义异常处理器
package com.ruki.exception;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SysExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
SysException e = null;
if(ex instanceof SysException){
e = (SysException)ex;
} else{
e = new SysException("系统正在维护");
}
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg", e.getMessage());
mv.setViewName("error");
return mv;
}
}
3.2.4 配置异常处理器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.ruki"></context:component-scan>
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="sysExceptionResolver" class="com.ruki.exception.SysExceptionResolver"></bean>
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
- 这句话最重要
<bean id="sysExceptionResolver" class="com.ruki.exception.SysExceptionResolver"></bean>
四、SpringMVC中的拦截器
- Spring MVC 的处理器拦截器类似于
Servlet
开发中的过滤器Filter
,用于对处理器进行预处理和后处理。 用户可以自己定义一些拦截器来实现特定的功能。
4.1 拦截器interceptor和过滤器filter的区别
- 过滤器是servlet规范中的一部分,任何java web工程都可以使用。
- 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
- 过滤器在
url-pattern
中配置了<font color="red">/*</font>之后,可以对所有要访问的资源拦截。 - 拦截器它是只会拦截访问的控制器方法,如果访问的是jsp、html、css、image或者js是不会进行拦截的。
- 我们要想自定义拦截器, 要求必须实现:
HandlerInterceptor
接口。
4.2 自定义拦截器的步骤
4.2.1 自定义拦截器类并实现HandlerInterceptor接口
preHandle()
:预处理postHandle
:后处理afterCompletion
:最终处理
package com.ruki.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor111.....执行前");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor111.....执行后");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor111最后执行");
}
}
4.2.2 配置拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.ruki"></context:component-scan>
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/*"/>
<bean class="com.ruki.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/*"/>
<bean class="com.ruki.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
- 其中最重要的部分:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/*"/>
<bean class="com.ruki.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
4.3 拦截器的细节
4.3.1 拦截器的放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor111.....执行前");
return true;
}
- 当返回值为
true
时,才是放行。
4.3.2 拦截器中方法的说明
preHandle()
:预处理- 按照拦截器定义顺序调用
postHandle
:后处理- 按照拦截器定义逆序调用
- 在业务处理器处理完请求后,但是
DispatcherServlet
向客户端返回响应前被调用
afterCompletion
:最终处理- 在
DispatcherServlet
完全处理完请求后被调用 - 可以在该方法中进行一些资源清理的操作
- 在
4.3.3 拦截器的作用路径
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/*"/>
<bean class="com.ruki.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
<mvc:mapping path="/**" />
- 用于指定对拦截的url
<mvc:exclude-mapping path=""/>
- 用于指定排除的url