目录
- SpringMVC
- SpringMVC简介
- 1、什么是MVC
- 2、什么是SpringMVC
- 3、SpringMVC的特点
- SpringMVC入门
- (1)引入依赖
- (2)配置web.xml
- (3)创建请求控制器
- (4)创建SpringMVC的配置文件
- (5)创建index.html
- (6)编辑control层
- (7)测试
- (8)补充:将配置文件设置到resources下
- classpath是什么:
- (9)总结
- @RequestMapping注解
- 1、@RequestMapping注解的功能
- 2、@RequestMapping注解的位置
- 3、@RequestMapping注解的value属性
- 4、@RequestMapping注解的method属性
- 5、@RequestMapping注解的params属性
- 6、@RequestMapping注解的headers属性
- 7、SpringMVC支持ant风格的路径
- ***但上面所有的ant符号都不能写问号"?"***
- 8、SpringMVC支持路径中的占位符(重点)
- SpringMVC获取请求参数
- 1、通过servletAPI获取
- 2、通过控制器方法的形参获取
- 3、通过pojo实体类类型的形参获取
- 4、解决获取请求参数的中文乱码问题
- 域对象共享数据
- 1、使用servletAPI向request域对象共享数据
- 2、使用ModelAndView向request域对象共享数据
- 3、使用Model、ModelMap、Map向request域对象共享数据
- 4、向session域对象共享数据
- 4、向application域对象共享数据
- springMVC视图
- 1、ThymeleafView
- 2、InternalResouceView(转发视图)
- 3、RedirectView(重定向视图)
- 4、视图控制器view-controller
- RESTful
- 1、RESTful简介
- 2、RESTful的实现
- 3、查询功能实现
- 4、使用HiddenHttpMethodFilter实现put、delete的改删功能
- 5、处理静态资源无法找到(CSS..)
- 6、RESTful实例(员工增删改查)
- springMVC处理ajax请求
- 1、@RequestBody
- 2、@ResponseBody
- 3、@RestController注解
- 文件上传和下载
- 1、下载
- 2、上传
- 拦截器
- 多个拦截器执行顺序
- 异常处理
- xml配置处理异常
- 注解配置处理异常
- 注解配置SpringMVC
SpringMVC
SpringMVC简介
1、什么是MVC
MVC是一种软件架构的思想,将软件按照模型、视图、控制器划分
M:Model,模型层,指工程中的JavaBean,作用是处理数据
Javabean分为两类:
- 实体类bean:专门储存业务数据的,如uesr
- 业务处理bean:指service或dao对象,专门用于处理业务逻辑和数据访问
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC工作流程:
用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
2、什么是SpringMVC
SpringMVC是Spring的一个后续产品,是spring的一个子项目
SpringMVC是spring为表述层开发(servlet)提供的一个框架,SpringMVC就是封装了servlet
三层架构分为表述层(表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
3、SpringMVC的特点
(1)Spring家族原生产品,与IoC容器对接
(2)基于原生的servlet,通过封装的servlet管理控制器DispatcherServlet,对请求和响应进行统一处理
(3)表述层各个细分领域需要解决的问题全方位覆盖,提供全面解决方案
(4)提高开发效率
(5)内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应的组件即可
SpringMVC入门
建议用tomcat10版本以下去测试
(1)引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- servletAPI -->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- slf4j日志门面的一个具体实现 -->
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
<scope>test</scope>
</dependency>
<!-- spring5和hymeleaf整合包 -->
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.15.RELEASE</version>
</dependency>
(2)配置web.xml
注意:
SpringMVC的配置文件默认的位置和名称:
位置:WEB-INF下
名称:-servlet.xml,以下配置的文件名称为SpringMVC-servlet.xml
url-pattern中/和/*的区别:
- /:匹配浏览器向服务器发送的所有请求(不包括.jsp)
- /*:匹配浏览器向服务器发送的所有请求(包括.jsp)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Archetype Created Web Application</display-name>
<!-- 配置SpringMVC的前端控制器DispatcherServlet -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
(3)创建请求控制器
由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器
请求控制器中每一个请求处理的方法成为控制器方法
因为springMVC的控制器由一个pojo(普通的Java类)担任,因此需要提通过@Controller注解将其标识为一个控制层组件
@Controller
public class HelloController {
}
(4)创建SpringMVC的配置文件
当前文件名为:SpringMVC-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="controller"></context:component-scan>
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
</beans>
(5)创建index.html
在/WEB-INF/templates/下创建index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!-- xmlns:th="http://www.thymeleaf.org": 引入thymeleaf -->
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>Hello World!</h2>
<a th:href="@{/hello }">测试SpringMVC</a>
<a href="/hello">测试绝对路径</a>
</body>
</html>
以及success.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>success</h1>
</body>
</html>
(6)编辑control层
@Controller
public class HelloController {
@RequestMapping("/")
public String protal() {
//将index.html
return "index";
}
@RequestMapping("/hello")
public String hello() {
return "success";
}
}
(7)测试
开启tomcat9测试
(8)补充:将配置文件设置到resources下
在web.xml中修改servlet配置
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 初始化配置
classpath:将springmvc配置文件转到resources下
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--
不在浏览器开启第一时间去访问DispatcherServlet:将DispatcherServlet的初始化时间提前到服务器启动时
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
classpath是什么:
classpath直译过来是类路径,是Java环境配置中要设置的一个环境变量,就是.class文件的路径,表示JVM从哪里去寻找要运行的class文件,classpath = D:\java表示执行java命令时去D:\java目录中去找需要被执行的class文件并运行。
一般一个web工程中java、resources下的路径都是类路径。
src/main/
下面的java
和resources
文件夹都被(编译)打包到了生产包的WEB-INF/classes/
目录下;而原来WEB-INF下面的views和web.xml则仍然还是在WEB-INF下面。同时由maven引入的依赖都被放入到了WEB-INF/lib/
下面。最后,编译后的class文件和资源文件都放在了classes目录下。
(9)总结
浏览器发送请求,若请求地址符合前端控制器的url—pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面
@RequestMapping注解
1、@RequestMapping注解的功能
从注解名称上可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
springMVC接收到指定的请求,就会去找到在映射关系中对应的控制器方法来处理这个请求。
2、@RequestMapping注解的位置
@RequestMapping注解标识一个类:设置映射请求的请求路径的初始信息
@RequestMapping注解标识一个方法:设置映射请求路径的具体信息
@Controller
@RequestMapping("/test")
public class HelloController {
//此时的hello方法的url路径为../test/hello,而不是../hello
@RequestMapping("/hello")
public String hello() {
return "success";
}
}
3、@RequestMapping注解的value属性
作用:通过请求的请求路径匹配请求
value属性是数组类型,即当前浏览器所发送请求的请求路径匹配value属性中的任何一个值,则当前请求就会被注解所标识的方法进行处理
@AliasFor("path")
String[] value() default {};
@RequestMapping({"/hello","/abc"})
public String hello() {
return "success";
}
4、@RequestMapping注解的method属性
作用:通过请求的请求方式匹配请求
method属性是@RequestMethod 类型的数组,即当前浏览器所发送请求的请求方式匹配method属性中的任何一个值,则当前请求就会被注解所标识的方法进行处理
若浏览器所发送的请求的请求路径和@RequestMapping注解的value属性所匹配,但与method属性不匹配,则此时页面会报错:
405 - Request method ‘GET’ not supported
RequestMethod[] method() default {};
public enum RequestMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}
@RequestMapping(value = {"/hello","/abc"},method = RequestMethod.POST)
public String hello() {
return "success";
}
@RequestMapping(value = {"/hello","/abc"},method = {RequestMethod.POST,RequestMethod.GET})
在@RequestMapping注解的基础上,结合请求方式的一些派生注解:
@GetMapping,@PostMapping,@DeleteMapping,@PutMapping
5、@RequestMapping注解的params属性
作用:通过请求的请求参数匹配请求,即浏览器发送的请求的请求参数必须满足pamas属性
params 可以使用四种表达式:
“param”:表示当前所匹配请求的请求参数中必须携带param参数
“!param”:表示当前所匹配请求的请求参数中一定不能携带param参数
“param=value”:表示当前所匹配请求的请求参数中必须携带param参数且值必须是value
“param!=value”:表示当前所匹配请求的请求参数中可以不携带param参数,若携带值一定不能是value
String[] params() default {};
@RequestMapping(value = {"/hello","/abc"},
method = {RequestMethod.POST,RequestMethod.GET},
// params = {"username"}
// params = {"username","!password"}
params = {"username","!password","age=10","admin!=18"})
public String hello() {
return "success";
}
若浏览器所发送的请求的请求路径和@RequestMapping注解value属性匹配,但是请求参数不匹配,则报错:
400 - Parameter conditions “username” not met for actual request parameters:
400 - Parameter conditions “username, !password” not met for actual request parameters: username={12}, password={}
6、@RequestMapping注解的headers属性
作用:@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射
@RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系
“header”:表示当前所匹配请求的请求头中必须携带header参数
“!header”:表示当前所匹配请求的请求头中一定不能携带header参数
“header=value”:表示当前所匹配请求的请求头中必须携带header参数且值必须是value
“header!=value”:表示当前所匹配请求的请求头中可以不携带header参数,若携带值一定不能是value
String[] headers() default {};
跟上面的params是差不多一样的
7、SpringMVC支持ant风格的路径
?:表示任意的单个字符
*:表示任意的0个或多个字符
**:表示任意层数的任意目录
注意:在使用 ** 时,只能使用 /** /XXX 的方式, ** 只能写在双斜线中,前后不能有任何的其它字符
@RequestMapping("/a?a/ant")
public String testAnt() {
return "success";
}
但上面所有的ant符号都不能写问号"?"
@RequestMapping("/**/ant")
public String testAnt() {
return "success";
}
8、SpringMVC支持路径中的占位符(重点)
原始方式:/XXX?id=1
rest方式:/XXX/1
SpringMVC路径中的占位符常用RESTful(后面有讲到)风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中占位符{XXX}表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参
<a th:href="@{/test/rest/1/admin}">SpringMVC支持路径中的占位符</a>
@RequestMapping("/test/rest/{id}/{username}")
public String testRest(@PathVariable("id") Integer id,@PathVariable("username") String uesrname) {
System.out.println("id:"+id+";username:"+uesrname);
return "success";
}
SpringMVC获取请求参数
1、通过servletAPI获取
将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象
@RequestMapping("/param/servletAPI")
public String getAPI(HttpServletRequest request) {
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(username + password);
return "success";
}
2、通过控制器方法的形参获取
@RequestParam:将请求参数和控制器方法的形参绑定
value/name:设置和形参绑定的请求参数的名字
required:设置是否必须传输value所对应的请求参数
默认值为true,表示value所对应的请求参数必须传输,否则页面报错
@RequestHeader:将请求头信息和控制器方法的形参绑定
@CookieValue:将cookie数据和控制器方法的形参绑定
@RequestMapping("/param")
public String getcontrolAPI(@RequestParam(name = "userName",required = false,defaultValue = "hai") String username,
String password,
@RequestHeader("referer") String referer,
@CookieValue("JSSESSIONID") String jssessioid) {
System.out.println(username + password);
return "success";
}
3、通过pojo实体类类型的形参获取
需要在控制器方法的形参位置设置实体类类型的形参,要保证实体类中的属性名和请求参数的名字一致
可以通过实体类类型的形参获取请求参数
4、解决获取请求参数的中文乱码问题
spring自带过滤器,通过再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>
<!-- 响应 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:
springmvc的自带过滤器一定要配置在其它过滤器前,否则无效
域对象共享数据
1、使用servletAPI向request域对象共享数据
@RequestMapping("/test/api")
public String api(HttpServletRequest request) {
request.setAttribute("test", "hello,api");
return "success";
}
<p th:text="${test}">
2、使用ModelAndView向request域对象共享数据
@RequestMapping("/test/view")
public ModelAndView view() {
/**
* ModelAndView包含model和view的功能
* model:向请求域中共享数据
* view:设置逻辑视图实现页面跳转
*/
ModelAndView modelAndView = new ModelAndView();
//向请求域中共享数据
modelAndView.addObject("test", "hello,modelandview");
modelAndView.setViewName("success");
return modelAndView;
}
3、使用Model、ModelMap、Map向request域对象共享数据
@RequestMapping("/test/model")
public String model(Model model) {
model.addAttribute("test", "hello,model");
return "success";
}
@RequestMapping("/test/modelMap")
public String modelMap(ModelMap modelMap) {
modelMap.addAttribute("test", "hello,modelMap");
return "success";
}
@RequestMapping("/test/map")
public String map(Map<String,Object> map) {
map.put("test", "hello,model");
return "success";
}
这三个方法都是一个类下所继承或接口
4、向session域对象共享数据
@RequestMapping("/test/session")
public String session(HttpSession session) {
session.setAttribute("test", "hello,sesssion");
return "success";
}
<p th:text="${session.test}">
4、向application域对象共享数据
@RequestMapping("/test/application")
public String application(HttpSession session) {
session.getServletContext().setAttribute("test", "hello,application");
return "success";
}
<p th:text="${application.test}">
注意:session和浏览器有关,在一次会话中只要浏览器不关闭就存在session;application是在整个应用域上,和服务器有关。
springMVC视图
springmvc中的视图是view接口,视图的作用是渲染数据,将模型model中的数据展示给用户
springmvc视图的种类很多,默认有转发视图和重定向视图
当工程引入jstl的依赖,转发视图会自动转换为jistlView
若使用的视图技术为Thymeleaf,在springmvc的配置文件中配置了Thymeleaf的视图解析器
1、ThymeleafView
当控制器方法中所设置的视图名没有任何前缀时,此时的视图名称会被springmvc配置文件中所配置的视图解析器解析
@RequestMapping("/**/ant")
public String testAnt() {
return "success";
}
2、InternalResouceView(转发视图)
@RequestMapping("/**/anti")
public String testAnt() {
return "forward:/test/view";
}
Thymeleaf和转发InternalResouce都可以实现转发,但如果用InternalResouce无法使Thymeleaf渲染页面,无法解析th语法,只是一个简单的a转发
3、RedirectView(重定向视图)
@RequestMapping("/**/anto")
public String testAnt() {
return "redirect:/test/view";
}
4、视图控制器view-controller
当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示
<!-- 开启mvc的注释驱动 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!--
path:设置处理的请求地址
view-controller:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
相当于:
@RequestMapping("/")
public String protal() {
//将index.html
return "index";
}
注意:
视图控制器:为当前的请求直接设置视图名称实现页面跳转,
若设置视图控制器,则只有视图控制器所设置的请求会被处理,其它的请求将全部404要在配置文件中设置<mvc:annotation-driven />
RESTful
1、RESTful简介
REST:表现层资源状态转移。
相当于传表单一样,用rest方法来传输客户端的数据给后端
2、RESTful的实现
在http协议中,有四个表示操作方式的动词:GET、POSY、PUT、DELETE.
GET用来获取资源、POST用来新建资源、PUT用来更新资源、DELETE用来删除资源
http方法 | 资源操作 | 幂等 | 安全 |
---|---|---|---|
GET | SELECT(查) | 是 | 是 |
POST | INSERT(增) | 否 | 否 |
PUT | UPDATE(改) | 是 | 否 |
DELETE | DELETE(删) | 是 | 否 |
幂等性:对同一REST接口的多次访问,得到的资源状态是相同的。
安全性:对该REST接口访问,不会使服务器端资源的状态发生改变。
3、查询功能实现
@RequestMapping(value = "/user/{id}" ,method=RequestMethod.GET)
public String getUserId(@PathVariable("id") Integer id) {
return "success";
}
同上@RequestMapping注解中的SpringMVC支持路径中的占位符(重点)讲到的一样
4、使用HiddenHttpMethodFilter实现put、delete的改删功能
因为客户端的请求方法只有GET、POST,不能直接用PUT、DELETE,所以需要一个过滤器来实现
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<form th:action="@{/user}" method="post">
<input type="hidden" name="_method" value="put">
<input type="submit" value="修改用户信息">
</form>
@RequestMapping(value = "/user" ,method=RequestMethod.PUT)
public String updateUserId() {
return "success";
}
delete方法和上面的put方法一样,用hidden来实现。
请求http方法:get --> /uesr/1 post --> /user put --> /user delete --> /user/1
5、处理静态资源无法找到(CSS…)
<link rel="stylesheet" href="/xxx/xxx.css">
在前端报错找不到xxx/xxx.css,原因是:
当前工程的web.xml配置的前端控制器DispacherServlet的url-pattern是/
此时,tomcat下的web.xml会先按照工程中web.xml下的配置进行,所以tomcat下的web.xml中的DefaultServlet不会去处理servlet 。浏览器发送到请求会优先被DispacherServlet进行处理,但是DispacherServlet无法处理静态资源。
解决方法是:在web.xml下配置<mvc:default-servlet-handler />和<mvc:annotation-driven />
若配置了<mvc:default-servlet-handler />,此时浏览器发送的请求都会被DefaultServlet处理
若配置了<mvc:default-servlet-handler />和<mvc:annotation-driven />
浏览器发送到请求会先被DispacherServlet处理,无法处理的交给DefaultServlet处理
<!-- 配置默认的servlet处理静态资源-->
<mvc:default-servlet-handler/>
<!-- 开启mvc的注释驱动 -->
<mvc:annotation-driven></mvc:annotation-driven>
6、RESTful实例(员工增删改查)
pojo
package pojo;
public class Employee {
private Integer id;
private String name;
private String sex;
public Employee(Integer id, String name, String sex) {
super();
this.id = id;
this.name = name;
this.sex = sex;
}
public Employee() {
super();
// TODO Auto-generated constructor stub
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", sex=" + sex + "]";
}
}
dao
package dao;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Repository;
import pojo.Employee;
@Repository
public class EmployeesImpl implements Employees {
private static Map<Integer, Employee> employees;
static {
employees = new HashMap<Integer, Employee>();
employees.put(1001, new Employee(1001,"小海","男"));
employees.put(1002, new Employee(1002,"小王","男"));
employees.put(1003, new Employee(1003,"小陈","女"));
}
private static int initid = 1004;
@Override
public int save(Employee employee) {
// TODO Auto-generated method stub
if (employee.getId() == null) {
employee.setId(initid++);
}
employees.put(employee.getId(), employee);
return 1;
}
@Override
public Employee getbyid(Integer id) {
// TODO Auto-generated method stub
return employees.get(id);
}
@Override
public int deletebyid(Integer id) {
// TODO Auto-generated method stub
employees.remove(id);
return -1;
}
@Override
public Collection<Employee> allEmployee() {
// TODO Auto-generated method stub
return employees.values();
}
}
springmvc.xml(配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="controller,dao,pojo"></context:component-scan>
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
<!-- 配置默认的servlet处理静态资源
当前工程的web.xml配置的前端控制器DispacherServlet的url-pattern是/
此时,浏览器发送到请求会优先被DispacherServlet进行处理,但是DispacherServlet无法处理静态资源
若配置了<mvc:default-servlet-handler />,此时浏览器发送的请求都会被DefaultServlet处理
若配置了<mvc:default-servlet-handler />和<mvc:annotation-driven />
浏览器发送到请求会先被DispacherServlet处理,无法处理的交给DefaultServlet处理
-->
<mvc:default-servlet-handler/>
<!-- 开启mvc的注释驱动 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 视图控制器:为当前的请求直接设置视图名称实现页面跳转
若设置视图控制器,则只有视图控制器所设置的请求会被处理,其它的请求将全部404
-->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<mvc:view-controller path="/to/add" view-name="add"></mvc:view-controller>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Archetype Created Web Application</display-name>
<!-- 配置SpringMVC的前端控制器DispatcherServlet
注意:
SpringMVC的配置文件默认的位置和名称:
位置:WEB-INF下
名称:<servlet-name>-servlet.xml,以下配置的文件名称为SpringMVC-servlet.xml
url-pattern中/和/*的区别:
/:匹配浏览器向服务器发送的所有请求(不包括.jsp)
/*:匹配浏览器向服务器发送的所有请求(包括.jsp)
-->
<!-- 配置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>
<!-- 响应 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>SpringMVC</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>
<!--
不在浏览器开启第一时间去访问DispatcherServlet:将DispatcherServlet的初始化时间提前到服务器启动时
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
controller
@Autowired
private EmployeesImpl employeesImpl;
//显示所有员工
@GetMapping("/employee")
public ModelAndView getallemployee(ModelAndView modelAndView) {
Collection<Employee> allEmployee = employeesImpl.allEmployee();
modelAndView.addObject("allEmployee",allEmployee);
modelAndView.setViewName("all");
return modelAndView;
}
//更新
@GetMapping("/employee/{id}")
public String getupdate(@PathVariable("id") Integer id,Model model) {
Employee employee = employeesImpl.getbyid(id);
model.addAttribute("employee", employee);
return "update";
}
@PutMapping("/employee")
public String update(Employee employee) {
employeesImpl.save(employee);
return "redirect:/employee";
}
//增加
@PostMapping("/employee")
public String add(Employee employee) {
employeesImpl.save(employee);
return "redirect:/employee";
}
//删除
@DeleteMapping("/employee/{id}")
public String getdelete(@PathVariable("id") Integer id) {
employeesImpl.deletebyid(id);
return "redirect:/employee";
}
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a th:href="@{/employee}">查询所有员工信息</a>
</body>
</html>
all.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div id="app">
<table>
<tr>
<th>id</th>
<th>name</th>
<th>sex</th>
<th>options(<a th:href="@{/to/add}">add</a>)</th>
</tr>
<tr th:each="employee : ${allEmployee}">
<td><p th:text=${employee.id}></td>
<td><p th:text=${employee.name}></td>
<td><p th:text=${employee.sex}></td>
<td>
<a th:href="@{'/employee/'+${employee.id}}">update</a>
<a @click="getfrom()" th:href="@{'/employee/'+${employee.id}}">delete</a>
<!-- <a οnclick="getfrom()" th:href="@{'/employee/'+${employee.id}}">delete</a> -->
</td>
</tr>
</table>
<form method="post">
<input type="hidden" name="_method" value="delete">
</form>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/javascript">
/* function getfrom(){
var form = document.getElementsByTagName("form")[0];
form.action = event.target.href;
form.submit();
event.preventDefault();
} */
var vue = new Vue({
el:"#app",
methods:{
getfrom(){
var form = document.getElementsByTagName("form")[0];
form.action = event.target.href;
form.submit();
event.preventDefault();
}
}
})
</script>
</html>
注意:< form method=“post”>没有action会自动提交,通过js来实现改变删除方法的请求方法
add.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form th:action="@{/employee}" method="post">
<input type="hidden" name="id">
性名:<input type="text" name="name"><br>
性别:<input type="radio" name="sex" value="男" >男<br>
<input type="radio" name="sex" value="女" >女<br>
<input type="submit" value="提交">
</form>
</body>
</html>
update.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form th:action="@{/employee}" method="post">
<input type="hidden" name="_method" value="put">
<input type="hidden" name="id" th:value="${employee.id}">
性名:<input type="text" name="name" th:value="${employee.name}"><br>
性别:<input type="radio" name="sex" value="男" >男<br>
<input type="radio" name="sex" value="女" >女<br>
<input type="submit" value="提交">
</form>
</body>
</html>
springMVC处理ajax请求
1、@RequestBody
将请求体中的内容和控制器方法的形参进行绑定
使用@RequestBody注解json格式的请求参数转换为Java对象
使用条件:
-
导入Jackson的依赖
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
-
在springmvc的配置文件中设置<mvc:annotation-driven />
-
在处理请求的控制器方法的形参位置,直接设置json格式的请求参数要转换的Java类型的形参,使用@RequestBody标识即可
<div id="app">
<a @click="testbody()" href="#">@RequestBody处理json请求参数</a>
</div>
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/javascript">
var vue = new Vue({
el:"#app",
methods:{
testbody(){
axios.post(
"/springMVC/test/ajax/RequestBody",
{id:1000,name:"小丁",sex:"男"}
).then(response=>{
console.log(response.data);
});
}
}
});
</script>
@RequestMapping("/test/ajax/RequestBody")
public void testajax(@RequestBody Employee employee,HttpServletResponse response) throws IOException {
System.out.println(employee);
response.getWriter().write("hello,ajax");
}
2、@ResponseBody
使用@ResponseBody注解响应浏览器json格式的数据
使用@ResponseBody注解java对象、map、list集合的请求参数转换为json格式
使用条件:
-
导入Jackson的依赖
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
-
在springmvc的配置文件中设置<mvc:annotation-driven />
-
将需要转换的json字符串的Java对象直接作为控制器方法的返回值,使用@ResponseBody注解标识控制器方法就可以将Java对象直接转换为json字符串,并响应到浏览器
注意:
常用的Java对象转换为json的结果:
实体类 --> json对象
map --> json对象
list --> json集合
testresponsebody(){
axios.post(
"/springMVC/test/ajax/responsebody"
).then(response=>{
console.log(response.data);
});
}
@RequestMapping("/test/ajax/responsebody")
@ResponseBody
public Employee testajax(){
Employee employee = new Employee(1006,"小王","男");
return employee;
}
3、@RestController注解
@RestController注解是springmvc提供的一个复合注解,表示在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解
文件上传和下载
1、下载
@RequestMapping("/test/down")
public ResponseEntity<byte[]> downfile(HttpSession session) throws IOException {
ServletContext context = session.getServletContext();
//文件名
String filename = "1.jpg";
File file = new File(filename);
//真实文件路径
String realPath = context.getRealPath("img") + file.separator +filename;
FileInputStream iStream = new FileInputStream(realPath);
//iStream.available()获取输入流所对应的文件字节数
byte[] bytes = new byte[iStream.available()];
//将流读到字节数组中
iStream.read(bytes);
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add("Content-disposition","attachment;filename="+filename);
//状态码
HttpStatus status = HttpStatus.OK;
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes,headers,status);
iStream.close();
return responseEntity;
}
注意:ResponseEntity<byte[]>的使用和理解
Spring ResponseEntity 详解:从原理到实践 - 知乎 (zhihu.com)
2、上传
使用spring封装的文件上传对象,通过此对象可以获取文件相关信息
文件上传要求from表单的请求方式必须是POST,并且添加属性enctype=“multipart/form-data”
<form th:action="@{/test/up}" method="post" enctype="multipart/form-data">
文件:<input type="file" name="photo"><br>
<input type="submit" value="提交">
</form>
使用springmvc上传文件步骤:
-
添加依赖
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> </dependency>
-
在springmvc的配置文件中配置
<!-- 配置文件上传解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
-
控制器方法
@RequestMapping("/test/up") public String upfile(MultipartFile photo,HttpSession session) throws IllegalStateException, IOException { //获取上下文 ServletContext context = session.getServletContext(); //获取文件的文件名 String filename = photo.getOriginalFilename(); /** *解决文件名重复的问题 *filename.lastIndexOf(".")标识文件名的最后一个.的位置 *filename.substring(filename.lastIndexOf("."))表示取到文件名的后缀名 *如文件名:1.png ,则hzname = .png **/ String hzname = filename.substring(filename.lastIndexOf(".")); //使用uuid String uuid = UUID.randomUUID().toString(); //用时间戳来重命名文件 filename = uuid + hzname; String path = context.getRealPath("photo"); File file = new File(path); if (!file.exists()) { //如果文件路径不存在,则创建文件 file.mkdir(); } String realpath = path + file.separator + filename; //利用MultipartFile获取文件的字节数据 photo.transferTo(new File(realpath)); return "success"; }
拦截器
SpringMVC中的拦截器用于拦截控制器方法的执行(在DispatcherServlet部署前配置)
SpringMVC中的拦截器需要实现HandlerInterceptor
拦截器需要在springmvc配置文件中配置:
<mvc:interceptors>
<!-- 两种配置方式都是对DispatcherServlet所处理的所有请求进行拦截 -->
<!-- <bean class="interceptor.FirstInterceptor"></bean> -->
<!-- <ref bean="firstInterceptor"></ref> -->
<mvc:interceptor>
<!-- /**表示项目下的路径都执行,/*只执行/下的路径,如/1/test不执行 -->
<mvc:mapping path="/**"/>
<ref bean="firstInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
注意:
配置ref 时需要FirstInterceptor类上加入@Component注解并扫描,让springmvcIOC去管理
类名的小驼峰命名是bean默认的id名
创建拦截类:
package interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class FirstInterceptor implements HandlerInterceptor{
//preHandle控制器方法执行前执行
//preHandle默认传参为true,如果为false则postHandle、afterCompletion不执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
//postHandle控制器方法执行后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
//afterCompletion渲染完视图后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
多个拦截器执行顺序
多个拦截器执行顺序跟springmvc配置文件下的配置顺序有关
<mvc:interceptors>
<ref bean="firstInterceptor"></ref>
<ref bean="secondInterceptor"></ref>
</mvc:interceptors>
输出顺序:
先执行firstInterceptor的preHandle,在执行secondInterceptor的preHandle,之后的postHandle、afterCompletion两个方法顺序相反。
异常处理
xml配置处理异常
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--
properties的键表示处理器方法执行过程中出现的异常
properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
-->
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!--
exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享
-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
注解配置处理异常
@ControllerAdvice
public class ExceptionController {
//异常处理,设置要处理的异常信息
//ArithmeticException.class 数学运算异常
@ExceptionHandler(ArithmeticException.class)
//Throwable ex 异常的形参
public String exption(Throwable ex,Model model) {
model.addAttribute("ex", ex);
return "error";
}
}
注解配置SpringMVC
在servlet3.0环境下,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置servlet容器(tomcat)。
spring提供了这个接口的实现,名为SpringServletContainerInitializer
1、配置weInit
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer{
//代替spring配置文件
@Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return new Class[] {SpringConfig.class};
}
//代替springMVC配置文件
@Override
protected Class<?>[] getServletConfigClasses() {
// TODO Auto-generated method stub
return new Class[] {WebConfig.class};
}
//设置springMVC的前端控制器的DispatcherServlet的url-pattern
@Override
protected String[] getServletMappings() {
// TODO Auto-generated method stub
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
//创建编码过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
//创建处理请求方式过滤器
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[] {characterEncodingFilter,hiddenHttpMethodFilter};
}
}
2、配置springmvc的配置文件
//将类标识为配置类
@Configuration
//扫描组件
@ComponentScan("controller")
//开启mvc注解驱动
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer{
//配置Thymeleaf视图解析器
//配置生成模板解析器
@Bean
public ServletContextTemplateResolver templateResolver() {
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
//生成模板引擎并为模板引擎注入模板解析器
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
//生成视图解析器并为解析器注入模板引擎
@Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setCharacterEncoding("UTF-8");
resolver.setTemplateEngine(templateEngine());
return resolver;
}
//处理静态资源
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
WebMvcConfigurer.super.configureDefaultServletHandling(configurer);
}
//配置视图控制器
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
WebMvcConfigurer.super.addViewControllers(registry);
}
//文件上传解析器
@Bean
//@Bean注解可以将标识的方法的返回值作为bean来管理
public CommonsMultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
//配置过滤器
@Override
public void addInterceptors(InterceptorRegistry registry) {
FirstInterceptor firstInterceptor = new FirstInterceptor();
registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
// TODO Auto-generated method stub
WebMvcConfigurer.super.configureHandlerExceptionResolvers(resolvers);
}
配置异常处理解析器
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("java.lang.ArithmeticException", "error");
simpleMappingExceptionResolver.setExceptionMappings(properties);
simpleMappingExceptionResolver.setExceptionAttribute("ex");
resolvers.add(simpleMappingExceptionResolver);
WebMvcConfigurer.super.extendHandlerExceptionResolvers(resolvers);
}
}