SpringMVC框架第二天
##SpringMVC大纲
1.SpringMVC返回分类
2.SpringMVC重定向和转发
3.SpringMVC实现JSON数据处理
4.SpringMVC文件上传
5.SpringMVC异常处理器定义
6.SpringMVC拦截器
重点:
掌握SpringMVC文件上传
掌握ModelAndView使用
掌握@ResponseBody的使用
掌握异常处理器定义
掌握拦截器的定义和使用
第1章:响应数据和结果视图
1.1 返回值分类
#####1.1.1 返回字符串
Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
@RequestMapping(value="/hello")
public String sayHello() {
System.out.println("Hello SpringMVC!!");
// 跳转到XX页面
return "success";
}
具体的应用场景
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 请求参数的绑定
*/
@RequestMapping(value="/initUpdate")
public String initUpdate(Model model) {
// 模拟从数据库中查询的数据
User user = new User();
user.setUsername("张三");
user.setPassword("123");
user.setMoney(100d);
user.setBirthday(new Date());
model.addAttribute("user", user);
return "update";
}
}
<h3>修改用户</h3>
${ requestScope }
<form action="user/update" method="post">
姓名:<input type="text" name="username" value="${ user.username }"><br>
密码:<input type="text" name="password" value="${ user.password }"><br>
金额:<input type="text" name="money" value="${ user.money }"><br>
<input type="submit" value="提交">
</form>
#####1.1.2 返回值是void
如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
可以使用请求转发或者重定向跳转到指定的页面
@RequestMapping(value="/initAdd")
public void initAdd(HttpServletRequest request,HttpServletResponse response) throws Exception {
System.out.println("请求转发或者重定向");
// 请求转发
// request.getRequestDispatcher("/WEB-INF/pages/add.jsp").forward(request, response);
// 重定向
// response.sendRedirect(request.getContextPath()+"/add2.jsp");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 直接响应数据
response.getWriter().print("你好");
return;
}
#####1.1.3 返回值是ModelAndView对象
ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图。
一会案例中我们将使用JSTL输出,所以需要引入jstl依赖包
在工程中引入jstl依赖
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
具体的代码如下
/**
* 返回ModelAndView对象
* 可以传入视图的名称(即跳转的页面),还可以传入对象。
* @return
* @throws Exception
*/
@RequestMapping(value="/findAll")
public ModelAndView findAll() throws Exception {
ModelAndView mv = new ModelAndView();
// 跳转到list.jsp的页面
mv.setViewName("list");
// 模拟从数据库中查询所有的用户信息
List<User> users = new ArrayList<>();
User user1 = new User();
user1.setUsername("张三");
user1.setPassword("123");
User user2 = new User();
user2.setUsername("赵四");
user2.setPassword("456");
users.add(user1);
users.add(user2);
// 添加对象
mv.addObject("users", users);
return mv;
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>查询所有的数据</h3>
<c:forEach items="${ users }" var="user">
${ user.username }
</c:forEach>
</body>
</html>
####1.2 SpringMVC框架提供的转发和重定向
#####1.2.1 forward请求转发
controller方法返回String类型,想进行请求转发也可以编写成
/**
* 使用forward关键字进行请求转发
* "forward:转发的JSP路径",不走视图解析器了,所以需要编写完整的路径
* @return
* @throws Exception
*/
@RequestMapping("/delete")
public String delete() throws Exception {
System.out.println("delete方法执行了...");
// return "forward:/WEB-INF/pages/success.jsp";
return "forward:/user/findAll";
}
#####1.2.2 redirect重定向
controller方法返回String类型,想进行重定向也可以编写成
/**
* 重定向
* @return
* @throws Exception
*/
@RequestMapping("/count")
public String count() throws Exception {
System.out.println("count方法执行了...");
return "redirect:/add.jsp";
// return "redirect:/user/findAll";
}
#####1.2.3 ResponseBody响应json数据
######1.2.3.1 DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
mvc:resources标签配置不过滤
1. location元素表示webapp目录下的包下的所有文件
2. mapping元素表示以/css开头的所有请求路径,如/css/a 或者/css/a/b
例如:将根目录/js目录下的所有文件映射成/js/**,也就说根目录下的js目录下文件都可以通过/js/xx来访问,例如:/js/1.jpg
<mvc:resources location="/js/" mapping="/js/**"/>
<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
######1.2.3.2 使用@RequestBody获取请求体数据
客户端往服务器传输数据的格式:
- “name=value&name=value&name=value…”
- ‘{“name”:“value”,“name”:“value”…}’
从前台传输一个和Address实体Bean对应的数据到后台,后台通过@RequestBody接收。实现流程如下:
创建Address
public class Address {
private String addressName;
private Integer addressNum;
//get..set..
}
创建AddressController,使用@RequestBody接收数据。
@Controller
@RequestMapping(value = "/address")
public class AddressController {
/***
* 使用@RequestBody接收整个提交内容体
* @param body
*/
@RequestMapping(value = "/add")
public void add(@RequestBody String body){
System.out.println(body);
}
}
创建index.jsp,引用jQuery,同时给按钮一个点击事件,点击按钮的时候,发送数据到后台。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>@RequestBody注解</title>
<script src="/js/jquery-2.2.3.min.js"></script>
<script>
$(function () {
//点击按钮发送请求参数
$('#btn').click(function () {
$.ajax({
url:'/address/add',
type:'post',
contentType:'application/json;charset=utf-8',
data:'{"addressName":"深圳市","addressNum":998}',
dataType:'json',
success:function (data) {
alert(data)
}
});
});
});
</script>
</head>
<body>
<button type="button" id="btn">发送请求</button>
</body>
</html>
######1.2.3.3 使用@RequestBody注解把json的字符串转换成JavaBean的对象
使用@RequestBody注解把json的字符串转换成JavaBean对象,此时需要引入jackson相关依赖包,当然,不一定非得用jackson的包,也可以用fastjson。
引入依赖
<!--用于JSON数据转换-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.6</version>
</dependency>
修改上面案例的add方法
/***
* 使用@RequestBody接收整个提交内容体,并转换成Address对象
* @param address
*/
@RequestMapping(value = "/add")
public void add(@RequestBody Address address){
System.out.println(address);
}
######1.2.3.4 使用@ResponseBody注解把JavaBean对象转换成json字符串,直接响应
我们把上面的案例稍微修改一下,在add方法上加上注解@ResponseBody,这样就能响应JSON数据了。页面就能拿到JSON数据。
修改add方法
/***
* 使用@RequestBody接收整个提交内容体,并转换成Address对象
* 方法上加上@ResponseBody注解,每次响应数据为JSON数据
* @param address
*/
@ResponseBody
@RequestMapping(value = "/add")
public Address add(@RequestBody Address address){
System.out.println(address);
return address;
}
修改jsp的js代码,直接输出addressName结点的值
//点击按钮发送请求参数
$('#btn').click(function () {
$.ajax({
url: '/address/add',
type: 'post',
contentType: 'application/json;charset=utf-8',
data: '{"addressName":"深圳市","addressNum":998}',
dataType: 'json',
success: function (data) {
alert(data.addressName)
}
});
});
如果使用RestController注解代替Controller注解,那么我们就可以不写ResponseBody注解了。
关于json的小结:首先保证项目中有json解析框架
- 将json类型的请求参数转换成JavaBean
- JavaBean的属性名和json中的key相同
- 给方法的JavaBean参数添加RequestBody注解
- 将方法返回的JavaBean转换成json字符串输出到客户端
- JavaBean的属性名和json中的key相同
- 给方法/类添加ResponseBody注解
- 或者将Controller注解改成RestController注解
第2章:SpringMVC实现文件上传
####2.1 Web上传文件
导入文件上传的jar包
commons-fileupload
commons-fileupload
1.3.1
commons-io
commons-io
2.4
编写文件上传的JSP页面
<h3>文件上传</h3>
<form action="/user/fileupload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传文件"/>
</form>
编写文件上传的Controller控制器
/**
* 文件上传
* @throws Exception
*/
@RequestMapping(value="/fileupload")
public String fileupload(HttpServletRequest request) throws Exception {
// 先获取到要上传的文件目录
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 创建File对象,一会向该路径下上传文件
File file = new File(path);
// 判断路径是否存在,如果不存在,创建该路径
if(!file.exists()) {
file.mkdirs();
}
// 创建磁盘文件项工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload fileUpload = new ServletFileUpload(factory);
// 解析request对象
List<FileItem> list = fileUpload.parseRequest(request);
// 遍历
for (FileItem fileItem : list) {
// 判断文件项是普通字段,还是上传的文件
if(fileItem.isFormField()) {
}else {
// 上传文件项
// 获取到上传文件的名称
String filename = fileItem.getName();
// 上传文件
fileItem.write(new File(file, filename));
// 删除临时文件
fileItem.delete();
}
}
return "success";
}
####2.2 SpringMVC文件上传
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。
代码如下
/**
* SpringMVC方式的文件上传
*
* @param request
* @return
* @throws Exception
*/
@RequestMapping(value="/fileupload2")
public String fileupload2(HttpServletRequest request,MultipartFile upload) throws Exception {
System.out.println("SpringMVC方式的文件上传...");
// 先获取到要上传的文件目录
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 创建File对象,一会向该路径下上传文件
File file = new File(path);
// 判断路径是否存在,如果不存在,创建该路径
if(!file.exists()) {
file.mkdirs();
}
// 获取到上传文件的名称
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把文件的名称唯一化
filename = uuid+"_"+filename;
// 上传文件
upload.transferTo(new File(file,filename));
return "success";
}
配置文件解析器对象
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
</bean>
####2.3 SpringMVC跨服务器方式文件上传
搭建图片服务器
1. 创建一个存储图片的Web项目,该项目中创建一个images文件夹,用于存放上传的图片
2. 将其部署到另外一个服务器中,并且启动
3. 注意俩服务器的端口不要一样
Tomcat默认是只读的,要实现跨服务器文件上传的话,就一定要设置Tomcat的readonly为false
怎么设置,通过修改Tomcat的web.xml文件
往DefaultServlet的配置的servlet标签中添加,下面的内容:
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
#####2.3.1 实现SpringMVC跨服务器方式文件上传
导入开发需要的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>
编写文件上传的JSP页面
<h3>跨服务器的文件上传</h3>
<form action="/user/fileupload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传文件"/>
</form>
编写控制器
/**
* SpringMVC跨服务器方式的文件上传
*
* @param request
* @return
* @throws Exception
*/
@RequestMapping(value="/fileupload3")
public String fileupload3(MultipartFile upload) throws Exception {
System.out.println("SpringMVC跨服务器方式的文件上传...");
// 定义图片服务器的请求路径
String path = "http://localhost:9090/day02_springmvc5_02image/uploads/";
// 获取到上传文件的名称
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 把文件的名称唯一化
filename = uuid+"_"+filename;
// 向图片服务器上传文件
// 创建客户端对象
Client client = Client.create();
// 连接图片服务器
WebResource webResource = client.resource(path+filename);
// 上传文件
webResource.put(upload.getBytes());
return "success";
}
第3章:SpringMVC的异常处理
####3.1 异常处理思路
Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理。
####3.2 自定义异常处理器
class ExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
//创建ModelAndView
ModelAndView md = new ModelAndView();
//指定友好的错误提示页面
md.setViewName("error");
//创建StringWriter
StringWriter stringWriter = new StringWriter();
//将错误信息输入进Stringwriter对象中
ex.printStackTrace(new PrintWriter(stringWriter));
//输出错误
System.out.println(stringWriter.toString());
return md;
}
}
####3.3 配置异常处理器
###第4章:SpringMVC框架中的拦截器
####4.1 拦截器的概述
- SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
- 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。
- 拦截器和过滤器的功能比较类似,有区别
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
- 拦截器也是AOP思想的一种实现方式
- 想要自定义拦截器,需要实现HandlerInterceptor接口。
####4.2自定义拦截器步骤
创建类,实现HandlerInterceptor接口,重写需要的方法
/**
* 自定义拦截器1
* @author rt
*/
public class MyInterceptor1 implements HandlerInterceptor{
/**
* controller方法执行前,进行拦截的方法
* return true放行
* return false拦截
* 可以使用转发或者重定向直接跳转到指定的页面。
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("拦截器执行了...");
return true;
}
}
####4.3 在springmvc.xml中配置拦截器类
mvc:interceptors
mvc:interceptor
<mvc:mapping path="/user/*"/>
</mvc:interceptor>
</mvc:interceptors>
####4.4 HandlerInterceptor接口中的方法
- preHandle方法是controller方法执行前拦截的方法
- 可以使用request或者response跳转到指定的页面
- return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
- return false不放行,不会执行controller中的方法。
- postHandle是controller方法执行后执行的方法,在JSP视图执行前。
- 可以使用request或者response跳转到指定的页面
- 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
- afterCompletion方法是在JSP执行后执行
- request或者response不能再跳转页面了
####4.5 配置多个拦截器
1)再编写一个拦截器的类
2)配置2个拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 哪些方法进行拦截 -->
<mvc:mapping path="/user/*"/>
<!-- 哪些方法不进行拦截
<mvc:exclude-mapping path=""/>
-->
<!-- 注册拦截器对象 -->
<bean class="com.itheima.demo1.MyInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<!-- 哪些方法进行拦截 -->
<mvc:mapping path="/**"/>
<!-- 注册拦截器对象 -->
<bean class="com.itheima.demo1.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
###MAVEN附录(pom.xml依赖)
<?xml version="1.0" encoding="UTF-8"?>
4.0.0
<groupId>com.itheima</groupId>
<artifactId>springmvc-day02-demo1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<!-- 版本锁定 -->
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<!--Spring相关依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
com.fasterxml.jackson.core
jackson-databind
2.9.6
com.fasterxml.jackson.core
jackson-core
2.9.6
com.fasterxml.jackson.core
jackson-annotations
2.9.6
<!--用于文件上传-->
<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>
<!--跨服务器上传文件-->
<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>
<!--ServletAPI-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>