本文已参与「新人创作礼」活动,一起开启掘金创作之路。
第三章 SpringMVC
3.1、基本概述
-
三层架构
-
咱们开发服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序
-
使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构
-
三层架构
- 表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型
- 业务层:处理公司具体的业务逻辑的
- 持久层:用来操作数据库的
-
-
MVC模型
- MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
- Model:数据模型,JavaBean的类,用来进行数据封装。
- View:指JSP、HTML用来展示数据给用户
- Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等。
3.2、SpringMVC的入门
搭建环境
- 创建web工程,导入开发的jar包
坐标导入
<!-- 版本锁定 -->
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<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>
<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>
</dependencies>
- 配置核心的控制器(配置DispatcherServlet)
web.xml中
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- resources目录下创建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="com.ywb"></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>
<!--开启SpringMVC框架注解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
-
编写index.jsp和HelloController控制器类
-
index.jsp
<body> <h3>入门案例</h3> <a href="${ pageContext.request.contextPath }/hello">入门案例</a> </body> -
HelloController
/** * @author yang * @date 2021年08月08日 23:21 * 控制器的类 */ @Controller public class HelloController { /** * 接收请求 * @return */ @RequestMapping(path = "/hello") public String sayHello(){ System.out.println("hello SpringMVC"); return "success"; } }
-
-
在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面
<body> <h3>入门成功!!</h3> </body> -
启动tomcat服务器,进行测试
过程分析
-
入门案例的执行流程
- 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件
- 开启了注解扫描,那么HelloController对象就会被创建
- 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法
- 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
- Tomcat服务器渲染页面,做出响应
-
入门案例中的组件分析
- 前端控制器(DispatcherServlet)
- 处理器映射器(HandlerMapping)
- 处理器(Handler)
- 处理器适配器(HandlAdapter)
- 视图解析器(View Resolver)
- 视图(View)
3.3、RequestMapping注解详解
-
RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
-
RequestMapping注解可以作用在方法和类上
- 作用在类上:第一级的访问目录
- 作用在方法上:第二级的访问目录
- 细节:路径可以不编写 / 表示应用的根目录开始
- ${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /
-
RequestMapping的属性
- path 指定请求路径的url
- value value属性和path属性是一样的
- method 指定该方法的请求方式
- params 指定限制请求参数的条件
- headers 发送的请求中必须包含的请求头
3.4、请求参数的绑定
-
请求参数的绑定说明
-
绑定机制
- 表单提交的数据都是k=v格式的 username=root&password=1234
- SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
- 要求:提交表单的name和参数的名称是相同的
-
支持的数据类型
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List、map集合等)
-
-
基本数据类型和字符串类型
- 提交表单的name和参数的名称是相同的
- 区分大小写
-
实体类型(JavaBean)
- 提交表单的name和JavaBean中的属性名称需要一致
- 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name
-
给集合属性数据封装
- JSP页面编写方式:list[0].属性
-
请求参数中文乱码的解决
-
在web.xml中配置Spring提供的过滤器类
<!--配置解决中文乱码的过滤器--> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--指定字符集--> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
实体类型(JavaBean)代码示例:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--请求参数绑定--%>
<%--
<a href="param/testParam?username=hehe&password=123">请求参数绑定</a>
--%>
<%--请求参数绑定封装到javaBean中
把数据封装到Account类中,Account类中有基本类型和User引用类型
--%>
<form action="param/saveAccount" method="post">
姓名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
金额:<input type="text" name="money"><br>
用户姓名:<input type="text" name="user.uname"><br>
用户年龄:<input type="text" name="user.age"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
ParamController控制器类:
/**
* @author yang
* @date 2021年08月09日 16:23
* 请求参数绑定
*/
@Controller
@RequestMapping("/param")
public class ParamController {
/**
* 请求参数绑定入门
* @return
*/
@RequestMapping("/testParam")
public String testParam(String username,String password){
System.out.println("testPram执行了。。。");
System.out.println("用户名:"+username);
System.out.println("密码:"+password);
return "success";
}
/**
* 请求参数绑定封装到JavaBean中
* @return
*/
@RequestMapping("/saveAccount")
public String saveAccount(Account account){
System.out.println("saveAccount执行了。。。");
System.out.println(account);
return "success";
}
}
集合类型代码示例:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--请求参数绑定封装到javaBean中
Account类型中有List集合和Map集合
--%>
<form action="param/saveAccount" method="post">
姓名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
金额:<input type="text" name="money"><br>
用户姓名:<input type="text" name="users[0].uname"><br>
用户年龄:<input type="text" name="users[0].age"><br>
用户姓名:<input type="text" name="userMap['one'].uname"><br>
用户年龄:<input type="text" name="userMap['one'].age"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
Account类:
public class Account implements Serializable {
private String username;
private String password;
private Double money;
private List<User> users;
private Map<String,User> userMap;
}
-
自定义类型转换器
-
表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换。
-
如果想自定义数据类型转换,可以实现Converter的接口
-
自定义类型转换器
/** * @author yang * @date 2021年08月10日 15:56 * 自定义类型转换器 */ public class StringToDateConverter implements Converter<String,Date> { @Override public Date convert(String s) { if (s==null){ throw new RuntimeException("请您传入数据"); } SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); try { //把字符串转换为日期 return df.parse(s); }catch (Exception e){ throw new RuntimeException("数据类型转换出现错误"); } } } -
注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!--配置自定义类型转换器--> <bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.ywb.utils.StringToDateConverter"></bean> </set> </property> </bean> <!--开启SpringMVC框架注解的支持--> <mvc:annotation-driven conversion-service="conversionService2"></mvc:annotation-driven>
-
-
-
在控制器中使用原生的ServletAPI对象
- 只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象
3.5、常用的注解
-
RequestParam注解
-
作用:把请求中的指定名称的参数传递给控制器中的形参赋值
-
属性
- value:请求参数中的名称
- required:请求参数中是否必须提供此参数,默认值是true,必须提供
-
代码如下
/** * 测试RequestParam注解 * @return */ @RequestMapping("/testRequestParam") public String testRequestParam(@RequestParam(name = "name") String username){ System.out.println("testRequestParam执行了。。。"); System.out.println(username); return "success"; }<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <a href="anno/testRequestParam?name=哈哈">RequestParam</a> </body> </html>
-
-
RequestBody注解
-
作用:用于获取请求体的内容(注意:get方法不可以)
-
属性
- required:是否必须有请求体,默认值是true
-
注意点:在表单中需要加入
enctype="text/plain",否则会中文乱码 -
代码如下
/** * 测试RequestBody注解 * @return */ @RequestMapping("/testRequestBody") public String testRequestBody(@RequestBody String body){ System.out.println("testRequestBody执行了。。。"); System.out.println(body); return "success"; }<form action="anno/testRequestBody" method="post" enctype="text/plain"> 用户姓名:<input type="text" name="username"><br> 用户年龄:<input type="text" name="age"><br> <input type="submit" value="提交"> </form>
-
-
PathVariable注解
-
作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
-
属性
- value:指定url中的占位符名称
-
Restful风格的URL
-
请求路径一样,可以根据不同的请求方式去执行后台的不同方法
-
restful风格的URL优点
- 结构清晰
- 符合标准
- 易于理解
- 扩展方便
-
-
代码如下
/** * 测试PathVariable注解 * @return */ @RequestMapping("/testPathVariable/{sid}") public String testPathVariable(@PathVariable(value = "sid") String id){ System.out.println("testPathVariable执行了。。。"); System.out.println(id); return "success"; }<a href="anno/testPathVariable/10">PathVariable</a>
-
-
RequestHeader注解
-
作用:获取指定请求头的值
-
属性
- value:请求头的名称
-
代码如下
/** * 测试RequestHeader注解 * @return */ @RequestMapping("/testRequestHeader") public String testRequestHeader(@RequestHeader("Accept") String header){ System.out.println("testRequestHeader执行了。。。"); System.out.println(header); return "success"; }<a href="anno/testRequestHeader">RequestHeader</a>
-
-
CookieValue注解
-
作用:用于获取指定cookie的名称的值
-
属性
- value:cookie的名称
-
代码如下
/** * 测试CookieValue注解 * @return */ @RequestMapping("/testCookieValue") public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){ System.out.println("testCookieValue执行了。。。"); System.out.println(cookieValue); return "success"; }<a href="anno/testCookieValue">CookieValue</a>
-
-
ModelAttribute注解
-
作用
- 出现在方法上:表示当前方法会在控制器方法执行前先执行。
- 出现在参数上:获取指定的数据给参数赋值。
-
应用场景
- 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
-
具体的代码
-
修饰的方法有返回值
/** * 测试ModelAttribute注解 * @return */ @RequestMapping("/testModelAttribute") public String testModelAttribute(User user){ System.out.println("testModelAttribute执行了。。。"); System.out.println(user); return "success"; } /** * 该方法会先执行 * @param uname * @return */ @ModelAttribute public User showUser(String uname){ System.out.println("showUser方法执行了。。。"); //模拟数据库查询对象 User user = new User(); user.setUname(uname); user.setAge(20); user.setDate(new Date()); return user; } -
修饰的方法没有返回值
/** * 测试ModelAttribute注解 * @return */ @RequestMapping("/testModelAttribute") public String testModelAttribute(@ModelAttribute("abc") User user){ System.out.println("testModelAttribute执行了。。。"); System.out.println(user); return "success"; } /** * 没有返回值类型 * @param uname * @return */ @ModelAttribute public void showUser(String uname, Map<String,User> map){ System.out.println("showUser方法执行了。。。"); User user = new User(); user.setUname(uname); user.setAge(20); user.setDate(new Date()); map.put("abc",user); }
-
-
SessionAttributes注解
-
作用:用于多次执行控制器方法间的参数共享
-
属性
- value:指定存入属性的名称
-
代码如下
/** * @author yang * @date 2021年08月10日 16:27 */ @Controller @RequestMapping("/anno") @SessionAttributes(value = {"msg"}) //存入Session域的对象中 public class AnnoController { /** * 向request中存入值 * SessionAttributes注解 * @return */ @RequestMapping("/testSessionAttributes") public String testSessionAttributes(Model model){ System.out.println("testSessionAttributes执行了。。。"); model.addAttribute("msg","测试SessionAttributes"); return "success"; } /** * 从session中获取值 * SessionAttributes注解 * @return */ @RequestMapping("/getSessionAttributes") public String getSessionAttributes(ModelMap modelMap){ System.out.println("getSessionAttributes执行了。。。"); String msg = (String) modelMap.get("msg"); System.out.println("msg是:"+msg); return "success"; } /** * 清除session * SessionAttributes注解 * @return */ @RequestMapping("/delSessionAttributes") public String delSessionAttributes(SessionStatus status){ System.out.println("delSessionAttributes执行了。。。"); status.setComplete(); return "success"; } }
-
-
3.6、响应数据和结果视图
3.6.1、返回值分类
-
返回字符串
-
Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
@RequestMapping("/testString") public String testString(){ System.out.println("testString方法执行了。。。"); return "success"; } -
具体的应用场景
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/testString") public String testString(Model model){ System.out.println("testString方法执行了。。。"); //模拟从数据库中查找数据 User user = new User(); user.setUsername("root"); user.setPassword("1234"); user.setAge(19); model.addAttribute("user",user); return "success"; } }<html> <head> <title>Title</title> </head> <body> <h3>执行成功</h3> ${user.username} ${user.password} ${user.age} </body> </html>
-
-
返回值是void
-
如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
-
默认会跳转到@RequestMapping(value="/initUpdate") initUpdate的页面。
-
可以使用请求转发或者重定向跳转到指定的页面
@RequestMapping("/testVoid") public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("testVoid方法执行了。。。"); //编写请求转发的程序 //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response); //重定向 //response.sendRedirect(request.getContextPath()+"/index.jsp"); //设置中文乱码 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); //直接进行响应 response.getWriter().print("你好"); return; }
-
-
-
返回值是ModelAndView对象
-
ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
-
代码如下
/** * 返回值是ModelAndView * @return */ @RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ System.out.println("testModelAndView方法执行了。。。"); //创建ModelAndView对象 ModelAndView mv = new ModelAndView(); //模拟从数据库中查找数据 User user = new User(); user.setUsername("root"); user.setPassword("1234"); user.setAge(19); //把user对象存储到mv对象中,也会把user对象存入到request对象 mv.addObject("user",user); //跳转到哪个页面 mv.setViewName("success"); return mv; }
-
3.6.2、SpringMVC框架提供的转发和重定向
-
forward请求转发
-
controller方法返回String类型,想进行请求转发也可以编写成
/** * 使用关键字的方法进行转发或重定向 * @return */ @RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect方法执行了。。。"); //请求转发 return "forward:/WEB-INF/pages/success.jsp"; }
-
-
redirect重定向
-
controller方法返回String类型,想进行重定向也可以编写成
/** * 使用关键字的方法进行转发或重定向 * @return */ @RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect方法执行了。。。"); //重定向 return "redirect:/index.jsp"; // return "redirect:/user/findAll"; }
-
3.6.3、ResponseBody响应json数据
-
DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而 不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
-
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 --> -
使用@RequestBody获取请求体数据
<script> //页面加载,绑定单击事件 $(function () { $("#btn").click(function () { //alert("hello btn") //发送ajax请求 $.ajax({ //编写json格式,设置属性和值 url:"user/testAjax", contentType:"application/json;charset=UTF-8", data:'{"username":"测试ajax","password":"12345","age":19}', dataType:"json", type:"post", success:function (data) { } }) }) }) </script>@RequestMapping(value = "/testAjax") public void testAjax(@RequestBody String body){ System.out.println("testAjax方法执行了。。。"); System.out.println(body); } -
使用@RequestBody注解把json的字符串转换成JavaBean的对象,并把对象返回到data
/** * 模拟异步请求响应 */ @RequestMapping(value = "/testAjax") public @ResponseBody User testAjax(@RequestBody User user){ System.out.println("testAjax方法执行了。。。"); //客户端发送的ajax请求,传的是json字符串,spring框架把json字符串封装到user对象中 System.out.println(user); //做响应,模拟查找数据库 user.setUsername("查找的用户"); user.setAge(30); //做响应 return user; }<script> //页面加载,绑定单击事件 $(function () { $("#btn").click(function () { //alert("hello btn") //发送ajax请求 $.ajax({ //编写json格式,设置属性和值 url:"user/testAjax", contentType:"application/json;charset=UTF-8", data:'{"username":"测试ajax","password":"12345","age":19}', dataType:"json", type:"post", success:function (data) { //data为服务器响应的json数据,进行解析 alert(data); alert(data.username); alert(data.password); alert(data.age); } }) }) }) </script> -
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>
-
3.7、SpringMVC实现文件上传
3.7.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> -
编写文件上传的JSP页面
<html> <head> <title>Title</title> </head> <body> <h3>文件上传</h3> <form action="user/fileupload1" method="post" enctype="multipart/form-data"> 选择文件<input type="file" name="upload"><br> <input type="submit" value="上传"> </form> </body> </html> -
编写文件上传的Controller控制器
/** * 文件上传 * @return */ @RequestMapping("/fileupload1") public String fileupload1(HttpServletRequest request) throws Exception { System.out.println("fileupload1执行了。。。"); //使用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()){ //普通表单项 System.out.println("普通表单项"); }else { //上传文件项 System.out.println("上传文件项"); //获取上传文件的名称 String fileName = item.getName(); //完成文件上传 item.write(new File(path,fileName)); //删除临时文件 item.delete(); } } return "success"; }
3.7.2、SpringMVC传统方式文件上传
-
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的 name属性名称相同。
-
配置文件解析器对象
<!--配置文件解析器对象--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"></property> </bean> -
代码如下
/** * SpringMVC文件上传 * @return */ @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(); upload.transferTo(new File(path,filename)); return "success"; }
3.7.3、SpringMVC跨服务器方式文件上传
-
搭建图片服务器
- 根据文档配置tomcat8的服务器,现在是2个服务器
- 创建多一个项目fileuploadserver作为图片服务器
-
实现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> -
编写控制器
/** * 跨服务器文件上传 * @return */ @RequestMapping("/fileupload3") public String fileupload3(MultipartFile upload) throws Exception { System.out.println("跨服务器文件上传。。。"); //定义上传文件服务器路径 String path = "http://localhost:9090/uploads/"; //获取上传文件的名称 String filename = upload.getOriginalFilename(); //创建客户端服务器 Client client = Client.create(); //和图片服务器进行连接 WebResource resource = client.resource(path + filename); //上传文件 resource.put(upload.getBytes()); return "success"; }
-
3.8、SpringMVC的异常处理
-
异常处理思路
- Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进 行异常的处理。
-
SpringMVC的异常处理
-
自定义异常类
/** * @author yang * @date 2021年08月12日 16:04 * 自定义异常类 */ public class SysException extends Exception{ private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public SysException(String msg) { this.msg = msg; } } -
自定义异常处理器
/** * @author yang * @date 2021年08月12日 16:12 * 异常处理器 */ public class SysExceptionResolver implements HandlerExceptionResolver { /** * 处理异常业务逻辑 * @param httpServletRequest * @param httpServletResponse * @param o * @param e * @return */ @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { //获取到异常对象 SysException sysException = null; if (e instanceof SysException){ sysException = (SysException) e; }else { sysException = new SysException("系统正在维护..."); } //创建ModelAndView对象 ModelAndView mv = new ModelAndView(); mv.addObject("errorMsg",sysException.getMsg()); //跳转的页面 mv.setViewName("error"); return mv; } } -
配置异常处理器
<!--配置异常处理器对象--> <bean id="sysExceptionResolver" class="com.ywb.exception.SysExceptionResolver"></bean>
-
3.9、SpringMVC框架中的拦截器
-
拦截器的概述
-
SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
-
可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链 中的拦截器会按着定义的顺序执行。
-
拦截器和过滤器的功能比较类似,有区别
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
-
拦截器也是AOP思想的一种实现方式
-
想要自定义拦截器,需要实现HandlerInterceptor接口。
-
-
自定义拦截器步骤
-
创建类,实现HandlerInterceptor接口,重写需要的方法
/** * @author yang * @date 2021年08月12日 16:48 * 自定义拦截器 */ 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 false; 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"); } } -
在springmvc.xml中配置拦截器类
<!--配置拦截器--> <mvc:interceptors> <!--配置第一个拦截器--> <mvc:interceptor> <!--要拦截的具体方法--> <mvc:mapping path="/user/*"/> <!--不要拦截的方法 <mvc:exclude-mapping path=""/> --> <!--配置拦截器对象--> <bean class="com.ywb.interceptor.MyInterceptor1"></bean> </mvc:interceptor> <!--配置第二个拦截器--> <mvc:interceptor> <!--要拦截的具体方法--> <mvc:mapping path="/user/*"/> <!--不要拦截的方法 <mvc:exclude-mapping path=""/> --> <!--配置拦截器对象--> <bean class="com.ywb.interceptor.MyInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors> -
HandlerInterceptor接口中的方法
-
preHandle方法是controller方法执行前拦截的方法
- 可以使用request或者response跳转到指定的页面
- return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
- return false不放行,不会执行controller中的方法。
-
postHandle是controller方法执行后执行的方法,在JSP视图执行前。
- 可以使用request或者response跳转到指定的页面
- 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
-
postHandle方法是在JSP执行后执行
- request或者response不能再跳转页面了
-
-
3.10、JSON
- 导入包
- 在springmvc-servlet.xml中配置json乱码问题
用法:
ObjectMapper mapper = new ObjectMapper();
User user = new User();
String str = mapper.writeValueAsString(user);
JSON乱码问题配置(springmvc-servlet.xml):
JSON返回时间