文章目录
SpringMVC_2 响应数据、文件上传、异常处理、拦截器
一、响应数据和结果视图
1、返回值分类
(1)返回字符串
Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器解析为物理视图的地址。
@RequestMapping(value = "/hello")
public String sayHello() {
System.out.println("Hello SpringMVC!!");
// 跳转到XX页面
return "success";
}
具体的应用场景
/**
* 返回值是String
*
* @param model
* @return
*/
@RequestMapping("/testString")
public String testString(Model model) {
System.out.println("testString方法执行了");
//模拟从数据库查询出了User对象
User user = new User();
user.setUsername("彭于晏");
user.setPassword("123");
user.setAge(20);
//model对象 addAttribute第一个参数是key值,第二个参数是user对象
model.addAttribute("user", user);
return "success";
}
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>执行成功</h3>
${user.username}
${user.password}
</body>
</html>
注意点:
可将数据存储到model对象中,然后在success.jsp中用${user.username}将属性取出来
(2)返回值是void
如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
默认会跳转到 @RequestMapping("/testVoid") testVoid的页面。
可以使用请求转发或者重定向跳转到指定的页面
/**
* 返回值是void,默认情况会去寻找方法请求路径名的testVoid.jsp
*
* @param request response
* @return
*/
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("testVoid方法执行了");
//1、编写请求转发的程序,不会经过视图解析器,要将目录写完整
//request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
//2、重定向,重新发的新请求不能访问WEb—INF/pages里的页面的
//response.sendRedirect(request.getContextPath()+"/index.jsp");
//3、直接会进行响应,响应json数据
//设置解决中文乱码问题
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print("hello 你好");
return;//不想让后面的代码继续执行加一个return
}
(3)返回值是ModelAndView对象
ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
具体的代码如下
/**
* 返回ModelAndView
*
* @return
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
System.out.println("testModelAndView方法执行了");
//模拟从数据库查询出了User对象
User user = new User();
user.setUsername("吴彦祖");
user.setPassword("123123");
user.setAge(20);
//把user对象存储到mv对象中,也会把user对象存入到request对象
mv.addObject("user", user);
//跳转到哪个页面,这里会走视图解析器
mv.setViewName("success");
return mv;
}
注意: 在页面上上获取使用的是 requestScope.username 取的,所以返回 ModelAndView 类型时,浏
览器跳转只能是请求转发。
2、SpringMVC框架提供的请求转发和重定向
controller方法返回String类型,请求转发的代码如下
/**
* 使用关键字的方式进行转发或重定向
*
* @return
*/
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect() {
System.out.println("testForwardOrRedirect方法执行了");
//1、请求的转发,不会走视图解析器,将路径写完整
//return "forward:/WEB-INF/pages/success.jsp";
//2、重定向 不用加项目名,注意和转发不同
return "redirect:/index.jsp";
}
注意:
1、如果用了 forward:则路径必须写成实际视图 url,不能写逻辑视图。
它相当于“request.getRequestDispatcher(“url”).forward(request,response)”。使用请求转发,既可以转发到 jsp,也可以转发到其他的控制器方法。
2、使用redirect:如果是重定向到 jsp 页面,则 jsp 页面不能写在 WEB-INF 目录中,否则无法找到
3、ResponseBody响应json数据
前言: 该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的
数据如:json,xml 等,通过 Response 响应给客户端
DispatcherServlet 会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在 springmvc.xml 配置文件添加如下配置
(1)mvc:resources标签配置不过滤
location元素表示webapp目录下的包下的所有文件
mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
在springmvc.xml中
<!--前端控制器,哪些静态资源不拦截-->
<mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
(2) 使用@RequestBody获取请求体数据
json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
<!--json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
使用@RequestBody注解把json的字符串转换成JavaBean的对象
/**
* 模拟异步响应请求
* Ajax传的是json数据,获得请求体的内容,请求体的内容是传的json的字符串
*/
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user) {
System.out.println("testAjax方法执行了");
//客户端发送ajax请求,传的是json字符串,后端把json字符串封装到user对象中
System.out.println(user);
//做响应,模拟查询数据库
user.setUsername("zoick");
//做响应,返回的是对象,但是前端还是json数据
return user;
}
<script src="js/jquery.min.js"></script>
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function(){
// alert("hello btn");
// 发送ajax请求
$.ajax({
// 编写json格式,设置属性和值
url:"user/testAjax",//后台的请求方法
contentType:"application/json;charset=UTF-8",
data:'{"username":"hehe","password":"123","age":30}',//json数据,将会传到服务器
dataType:"json",
type:"post",
success:function(data){
// data服务器端响应的json的数据,进行解析
alert(data);
alert(data.username);
alert(data.password);
alert(data.age);
}
});
});
});
</script>
二、SpringMVC实现文件上传
0、文件上传的必要前提
1、form 表单的 enctype 取值必须是:multipart/form-data
(默认值是:application/x-www-form-urlencoded)
enctype:是表单请求正文的类型
2、method 属性取值必须是 Post
3、提供一个文件选择域<input type=”file” />
1、传统文件上传方式
(1)导入文件上传的jar包
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!--使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。-->
(2)文件上传的JSP页面
<h3>传统方式文件上传</h3>
<form action="user/fileupload1" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/> <br/>
<input type="submit" value="上传"/>
</form>
(3)文件上传的Controller控制器
@RequestMapping("/fileupload1")
public String fileupload1(HttpServletRequest request) throws Exception {
System.out.println("文件上传...");
//使用fileupload组件完成文件上传
//上传的位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
//判断该路径是否存在
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()) {
//true说明普通表单项
} else {
//说明上传文件项
//获取上传文件的名称
String filename = item.getName();
//把文件名设为唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = filename + uuid;
//完成文件上传
item.write(new File(path, filename));
//删除临时文件
item.delete();
}
}
return "success";
}
2、SpringMVC方式文件上传
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。
(1)在spring.mvc中配置文件解析器对象
<!--配置文件解析器对象 id值是固定的-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSizePerFile" value="10485760"/>
</bean>
注意: 文件上传的解析器 id 是固定的,不能起别的名称,否则无法实现请求参数的绑定。(不光是文件,其他字段也将无法绑定
(2)文件上传的JSP页面
<h3>SpringMVC文件上传</h3>
<form action="user/fileupload2" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/> <br/>
<input type="submit" value="上传"/>
</form>
(3)文件用SpringMVC框架上传的Controller控制器
@RequestMapping("/fileupload2")
//注意MultipartFile中形参的名字要和jsp中的表单的名字相同
public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("SpringMVC文件上传...");
//使用fileupload组件完成文件上传
//上传的位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
//判断该路径是否存在
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
//说明上传文件项
//获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
//完成文件上传
upload.transferTo(new File(path,filename));
return "success";
}
3、SpringMVC跨服务器方式文件上传
(1)搭建tomcat图片服务器
(2)导入所需要的jar包
<!--跨服务器上传需要的jar包-->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
(3)文件上传的JSP页面
<h3>跨服务器文件上传</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/> <br/>
<input type="submit" value="上传3"/>
</form>
(4)文件上传的Controller控制器
/**
* 跨服务器文件上传
* @return
*/
@RequestMapping("/fileupload3")
public String fileuoload3(MultipartFile upload) throws Exception {
System.out.println("跨服务器文件上传...");
// 定义上传文件服务器路径
String path = "http://localhost:9090/uploads/";
// 说明上传文件项
// 获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 创建客户端的对象
Client client = Client.create();
// 和图片服务器进行连接
WebResource webResource = client.resource(path + filename);
// 上传文件
webResource.put(upload.getBytes());
return "success";
}
三、SpringMVC的异常处理
1、异常处理思路
Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理。
2、SpringMVC的异常处理
(1)自定义异常类
@Getter
@Setter
public class SysException extends Exception{
//存储提示信息的
private String message;
public SysException(String message) {
this.message = message;
}
}
(2)自定义异常处理器
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 处理异常的业务逻辑
*
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param ex
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
//获取异常对象
SysException e = null;
if (ex instanceof SysException) {
//如果抛出的是系统自定义异常则直接转换
e = (SysException) ex;
}else {
//如果抛出的不是系统自定义异常则重新构造一个系统错误异常
e = new SysException("系统正在维护...");
}
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
mv.setViewName("error");
return mv;
}
}
(3)在spring.mvc中配置异常处理器
<!--配置异常处理器-->
<bean id="sysException" class="top.zoick.exception.SysExceptionResolver"/>
四、SpringMVC框架中的拦截器
1、拦截器的概述
1、SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
2、可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链
中的拦截器会按着定义的顺序执行。
3、拦截器和过滤器的功能比较类似,有区别
过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
拦截器是SpringMVC框架独有的。
过滤器配置了/*,可以拦截任何资源。
拦截器只会对控制器中的方法进行拦截。
4、拦截器也是AOP思想的一种实现方式
5、想要自定义拦截器,需要实现HandlerInterceptor接口。
2、自定义拦截器步骤
(1)创建类,实现HandlerInterceptor接口,重写需要的方法
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 预处理,controller方法执行前,实际开发场景:登录页面是否登录的逻辑判断
* return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
* return false 不放行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了......前111");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
/**
* 后处理方法,此方法执行与controller方法执行后,success.jsp执行前
* 可用来释放资源,关闭流
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了......后111");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
/**
* success.jsp方法执行后,该方法会执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了......最后111");
}
}
(2)在springmvc.xml中配置多个拦截器类
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截的具体方法-->
<mvc:mapping path="/user/*"/>
<!--配置拦截器对象-->
<bean class="top.zoick.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<!--配置第二个拦截器-->
<mvc:interceptor>
<!--要拦截的具体方法-->
<mvc:mapping path="/**"/>
<!--配置拦截器对象-->
<bean class="top.zoick.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
(3)多个拦截器执行流程
3、HandlerInterceptor接口中的方法
(1)preHandle方法是controller方法执行前拦截的方法
可以使用request或者response跳转到指定的页面
return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
return false不放行,不会执行controller中的方法。
(2)postHandle是controller方法执行后执行的方法,在JSP视图执行前。
可以使用request或者response跳转到指定的页面
如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
(3)postHandle方法是在JSP执行后执行
request或者response不能再跳转页面了