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;
}
}
<!--配置异常处理器-->
<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>