SpringMVC学习之路 第二篇
- 在第一篇的基础上,今天我们继续学习SpringMVC框架。
- 本文涉及以下内容:
1. 响应数据返回值 。
2. ResponseBody 响应 json 数据 。
3. SpringMVC实现文件上传 。
4. SpringMVC异常处理 。
5. SpringMVC拦截器 。
1. 响应数据返回值 |
- 响应数据的返回值有String类型、void类型和ModelAndView。
1.1 返回值类型是String类型:
- 顺便复习下Attribute
- 编写response.jsp文件:
<a href="user/testString">testString</a>
- 编写User类(domain/User.java),忽略get等方法:
public class User implements Serializable { private String username; private String password; private Integer age;
- 编写UserController类(controller/UserController.java):
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/testString") public String testString(Model model) { System.out.println("testString方法执行了"); //模拟从数据库拿User对象 User user = new User(); user.setUsername("美美"); user.setPassword("123"); user.setAge(25); //model对象 model.addAttribute("user", user); return "success"; } }
- 编写成功跳转页面success.jsp(WEB-INF/pages/success.jsp):
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head> <title>Title</title> </head> <body> <h3>执行成功。。。</h3> ${user.username} ${user.password} ${user.age} </body> </html>
1.2 返回值类型是void类型:
- 转发和重定向的区别如下:
- request.getRequestDispatcher().forward(request,response):
- 属于转发,也是服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求,前后页共用一个request,可以通过此来传递一些数据或者session信息,request.setAttribute()和request.getAttribute()。
- 在前后两次执行后,地址栏不变,仍是当前文件的地址。
- 不能转向到本web应用之外的页面和网站,所以转向的速度要快。
- URL中所包含的“/”表示应用程序(项目)的路径。
- response.sendRedirect():
- 属于重定向,也是客户端跳转,相当于客户端向服务端发送请求之后,服务器返回一个响应,客户端接收到响应之后又向服务端发送一次请求,一共是2次请求,前后页不共用一个request,不能读取转向前通过request.setAttribute()设置的属性值。
- 在前后两次执行后,地址栏发生改变,是目标文件的地址。
- 可以转向到本web应用之外的页面和网站,所以转向的速度相对要慢。
- URL种所包含的"/"表示根目录的路径。
- 增加response.jsp的内容:
<a href="user/testVoid">testVoid</a>
- 若不写返回值,也没有转发和重定向,它会默认跳转到WEB-INF/pages/user/testVoid.jsp。我们可以在它默认的位置编写相应的jsp文件就可以啦。看UserCOntroller代码:
@Controller @RequestMapping("/user") public class UserController { estMapping("/testVoid") public void testVoid() { System.out.println("testVoid方法执行了"); } }
- 采用请求转发模式,编写UserController:
@RequestMapping("/testVoid") public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("testVoid方法执行了"); //编写请求转发的程序 request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response); }
- 采用response页面重定向,编写UserController:
@RequestMapping("/testVoid") public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("testVoid方法执行了"); //重定向 response.sendRedirect(request.getContextPath()+"/index.jsp");
- 直接进行响应的方式:
@RequestMapping("/testVoid") public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("testVoid方法执行了"); //直接会进行响应 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); response.getWriter().println("你好,世界"); }
1.3 返回值类型是ModeAndView类型:
- 前面返回值String类型(和Model)底层就是用这种方式实现的。
- 编写response.jsp:
<a href="user/testModelAndView">testModelAndView</a>
- 编写UserController类:
@RequestMapping("/testModelAndView") public ModelAndView testModelAndView() { //创建ModelAndView对象 ModelAndView mv = new ModelAndView(); System.out.println("testModelAndView方法执行了"); //模拟从数据库拿User对象 User user = new User(); user.setUsername("美美"); user.setPassword("123"); user.setAge(25); //把user对象存储在mv对象中,也把user对象存入到request对象 mv.addObject("user", user); mv.setViewName("success"); return mv; }
1.4 用关键字做转发和重定向:
- 编写response.jsp:
<a href="user/testForwardOrRedirect">testModelAndView</a>
- 编写UserController类:
@RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect() { System.out.println("testString方法执行了"); //请求的转发 //return "forward:/WEB-INF/pages/success.jsp"; //重定向 return "redirect:/index.jsp"; }
2. ResponseBody 响应 json 数据 |
2.1 过滤静态资源,哪些静态资源不被拦截
- 添加css,images,js等目录
- webapp/css webapp/images webapp/js
- 在springmvc.xml中配置:
<!--前端控制器,哪些静态资源不拦截--> <mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/images/" mapping="/images/**"/> <mvc:resources location="/js/" mapping="/js/**" />
2.2 发送ajax请求
-
导入jquery包。
将jquery.min.js包导入到webapp/js中 -
编写response.jsp(webapp/response.jsp):
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</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":"hehe","password":"123","age":30}', dataType: "json", type: "post", success: function (data) { //data服务器端响应的json数据,进行解析 alert(data); alert(data.username); alert(data.password); alert(data.age); } }); }); }); </script> </head> <body> <button id="btn">发送ajax</button> </body> </html>
-
添加jackson包,让springmvc支持json数据格式的解析和和转换,在pom.xml添加如下:
<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>
-
添加UserController中内容:
-
返回值User前面也要用ResponseBody注解,表示返回的是json类型的。
//模拟异步请求响应 @RequestMapping("/testAjax") public @ResponseBody User testAjax(@RequestBody User user) { System.out.println("testAjax方法执行了"); System.out.println(user); user.setUsername("haha"); user.setAge(40); return user; }
3. SpringMVC实现文件上传 |
3.1 文件上传之传统方式上传
- 编写index.jsp文件:
-
form 表单的 enctype 取值必须是:multipart/form-data,(默认值是:application/x-www-form-urlencoded)。
-
enctype:是表单请求正文的类型
-
multipart/form-data:指定传输数据为二进制数据,例如图片、mp3、文件
-
application/x-www-from-urlencoded:只能上传键值对,并且键值对都是间隔分开的。
<h3>传统文件上传</h3> <form action="/user/fileupload1" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"> <br> <input type="submit" value="上传"> </form>
- 在pom.xml中导入上传文件需要的包:
- commons-fileupload依赖于commons-i包
<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>
- 编写UserController:
@Controller @RequestMapping("/user") public class UserController { @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);// 文件上传对象 List<FileItem> items = upload.parseRequest(request); // 将表单中的所有数据信息放入 list容器中 for(FileItem item: items) { //进行判断,当前item对象是否是上传文件项 if(item.isFormField()) { //说明普通表单项 } else { //上传文件项 String filename = item.getName(); //获取名称 //用uuid更改为唯一的名称 String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid + "_" + filename; item.write(new File(path, filename)); //完成文件上传 item.delete(); //删除临时文件 } } return "success"; } }
3.2 文件上传之SpringMVC方式
- pom.xml中的commons-fileupload和commons-io包不能少
- 编写index.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>
- 在springmvc.xml中添加文件的解析器:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 开启注解扫描 --> <context:component-scan base-package="fang"/> <!-- 视图解析器对象 --> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> <!--前端控制器,哪些静态资源不拦截--> <mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/images/" mapping="/images/**"/> <mvc:resources location="/js/" mapping="/js/**"/> <!--配置文件解析器对象--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760" /> <!--10M--> </bean> <!-- 开启SpringMVC框架注解的支持 --> <mvc:annotation-driven /> </beans>
- 编写UserController:
- MultipartFile upload中的upload和< input type=“file” name=“upload” >中的name属性保持一致
@RequestMapping("/fileupload2") 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"; }
4. SpringMVC异常处理 |
4.1 编写index.jsp:
<h3>异常处理</h3>
<a href="user/testException">异常处理</a>
4.2 编写异常类(exception/SysException),省略get和set方法:
public class SysException extends Exception {
private String message;
public SysException(String message) {
this.message = message;
}
}
4.3 编写异常处理类(exception/SysExceptionResolver):
public class SysExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
SysException ex = null;
if(e instanceof SysException) {
ex = (SysException) e;
} else {
ex = new SysException("系统正在维护。。。");
}
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg", e.getMessage());//存入值
mv.setViewName("error");//跳转到error.jsp页面
return mv;
}
}
4.4 在springmvc.xml中添加异常处理器:
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="fang.exception.SysExceptionResolver"/>
4.5 编写error.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${errorMsg}
</body>
</html>
4.6 编写UserController:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testException")
public String testException() throws SysException {
System.out.println("testException执行了。。。");
try {
int a = 10 / 0;
} catch (Exception e) {
e.printStackTrace();
//抛出自定义异常信息
throw new SysException("查询用户出错");
}
return "success";
}
}
5. SpringMVC拦截器 |
- 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
- 拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程
- 才能用。
- 过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
- 拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。
- 我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
5.1 编写index.jsp:
<h3>拦截器</h3>
<a href="user/testInterceptor">拦截器</a>
5.2 编写拦截器类(interceptor/MyInterceptor):
- preHandle:方法执行之前拦截
- postHandle:方法执行之后,跳转页面执行之前拦截
- afterCompletion:跳转页面执行之后拦截
- preHandle方法返回值为false表示不放行,true为放行。
public class MyInterceptor1 implements HandlerInterceptor {
@Override //预处理,controller方法执行前
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request, response);
return true;//true放行,false不放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了...后");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了...最后");
}
}
5.3 编写成功跳转页面success.jsp:
- <% System.out.println(“success.jsp执行了。。。”); %>为java代码,会在控制台输出。
<h3>执行成功。。。</h3>
<% System.out.println("success.jsp执行了。。。"); %>
5.4 编写UserController类:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testInterceptor")
public String testInterceptor() {
System.out.println("testInterceptor执行了");
return "success";
}
}
5.5 在springmvc.xml中配置拦截器:
- path="/user/* 为拦截范围路径为/user下的所有目录,比如/user/testInterceptor
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/*"/> <!--要拦截的具体的方法-->
<!--<mvc:exclude-mapping path=""/>--> <!--不要拦截的方法-->
<!--配置拦截器对象-->
<bean class="fang.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>