MVC是一种软件架构的思想,将软件按照模型、视图、控制器划分
M:Model,模型层,指工程中的JavaBean,作用是处理数据
Javabean分为两类:
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC工作流程:
用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
SpringMVC是Spring的一个后续产品,是spring的一个子项目
SpringMVC是spring为表述层开发(servlet)提供的一个框架,SpringMVC就是封装了servlet
三层架构分为表述层(表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
(1)Spring家族原生产品,与IoC容器对接
(2)基于原生的servlet,通过封装的servlet管理控制器DispatcherServlet,对请求和响应进行统一处理
(3)表述层各个细分领域需要解决的问题全方位覆盖,提供全面解决方案
(4)提高开发效率
(5)内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应的组件即可
建议用tomcat10版本以下去测试
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.1version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.4.5version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring5artifactId>
<version>3.0.15.RELEASEversion>
dependency>
注意:
SpringMVC的配置文件默认的位置和名称:
位置:WEB-INF下
名称:-servlet.xml,以下配置的文件名称为SpringMVC-servlet.xml
url-pattern中/和/*的区别:
<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 Applicationdisplay-name>
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器
请求控制器中每一个请求处理的方法成为控制器方法
因为springMVC的控制器由一个pojo(普通的Java类)担任,因此需要提通过@Controller注解将其标识为一个控制层组件
@Controller
public class HelloController {
}
当前文件名为:SpringMVC-servlet.xml
<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>
<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>
在/WEB-INF/templates/下创建index.html
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
head>
<body>
<h2>Hello World!h2>
<a th:href="@{/hello }">测试SpringMVCa>
<a href="/hello">测试绝对路径a>
body>
html>
以及success.html
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
head>
<body>
<h1>successh1>
body>
html>
@Controller
public class HelloController {
@RequestMapping("/")
public String protal() {
//将index.html
return "index";
}
@RequestMapping("/hello")
public String hello() {
return "success";
}
}
在web.xml中修改servlet配置
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
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目录下。
浏览器发送请求,若请求地址符合前端控制器的url—pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面
从注解名称上可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
springMVC接收到指定的请求,就会去找到在映射关系中对应的控制器方法来处理这个请求。
@RequestMapping注解标识一个类:设置映射请求的请求路径的初始信息
@RequestMapping注解标识一个方法:设置映射请求路径的具体信息
@Controller
@RequestMapping("/test")
public class HelloController {
//此时的hello方法的url路径为../test/hello,而不是../hello
@RequestMapping("/hello")
public String hello() {
return "success";
}
}
作用:通过请求的请求路径匹配请求
value属性是数组类型,即当前浏览器所发送请求的请求路径匹配value属性中的任何一个值,则当前请求就会被注解所标识的方法进行处理
@AliasFor("path")
String[] value() default {};
@RequestMapping({"/hello","/abc"})
public String hello() {
return "success";
}
作用:通过请求的请求方式匹配请求
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
作用:通过请求的请求参数匹配请求,即浏览器发送的请求的请求参数必须满足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={}
作用:@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射
@RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系
“header”:表示当前所匹配请求的请求头中必须携带header参数
“!header”:表示当前所匹配请求的请求头中一定不能携带header参数
“header=value”:表示当前所匹配请求的请求头中必须携带header参数且值必须是value
“header!=value”:表示当前所匹配请求的请求头中可以不携带header参数,若携带值一定不能是value
String[] headers() default {};
跟上面的params是差不多一样的
?:表示任意的单个字符
*:表示任意的0个或多个字符
**:表示任意层数的任意目录
注意:在使用 ** 时,只能使用 /** /XXX 的方式, ** 只能写在双斜线中,前后不能有任何的其它字符
@RequestMapping("/a?a/ant")
public String testAnt() {
return "success";
}
@RequestMapping("/**/ant")
public String testAnt() {
return "success";
}
原始方式:/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";
}
将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";
}
@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";
}
需要在控制器方法的形参位置设置实体类类型的形参,要保证实体类中的属性名和请求参数的名字一致
可以通过实体类类型的形参获取请求参数
spring自带过滤器,通过再web.xml下设置过滤器就可以完成
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>forceEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
注意:
springmvc的自带过滤器一定要配置在其它过滤器前,否则无效
@RequestMapping("/test/api")
public String api(HttpServletRequest request) {
request.setAttribute("test", "hello,api");
return "success";
}
<p th:text="${test}">
@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;
}
@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";
}
这三个方法都是一个类下所继承或接口
@RequestMapping("/test/session")
public String session(HttpSession session) {
session.setAttribute("test", "hello,sesssion");
return "success";
}
<p th:text="${session.test}">
@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中的视图是view接口,视图的作用是渲染数据,将模型model中的数据展示给用户
springmvc视图的种类很多,默认有转发视图和重定向视图
当工程引入jstl的依赖,转发视图会自动转换为jistlView
若使用的视图技术为Thymeleaf,在springmvc的配置文件中配置了Thymeleaf的视图解析器
当控制器方法中所设置的视图名没有任何前缀时,此时的视图名称会被springmvc配置文件中所配置的视图解析器解析
@RequestMapping("/**/ant")
public String testAnt() {
return "success";
}
@RequestMapping("/**/anti")
public String testAnt() {
return "forward:/test/view";
}
Thymeleaf和转发InternalResouce都可以实现转发,但如果用InternalResouce无法使Thymeleaf渲染页面,无法解析th语法,只是一个简单的a转发
@RequestMapping("/**/anto")
public String testAnt() {
return "redirect:/test/view";
}
当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示
<mvc:annotation-driven>mvc:annotation-driven>
<mvc:view-controller path="/" view-name="index">mvc:view-controller>
相当于:
@RequestMapping("/")
public String protal() {
//将index.html
return "index";
}
注意:
视图控制器:为当前的请求直接设置视图名称实现页面跳转,
若设置视图控制器,则只有视图控制器所设置的请求会被处理,其它的请求将全部404要在配置文件中设置
REST:表现层资源状态转移。
相当于传表单一样,用rest方法来传输客户端的数据给后端
在http协议中,有四个表示操作方式的动词:GET、POSY、PUT、DELETE.
GET用来获取资源、POST用来新建资源、PUT用来更新资源、DELETE用来删除资源
http方法 | 资源操作 | 幂等 | 安全 |
---|---|---|---|
GET | SELECT(查) | 是 | 是 |
POST | INSERT(增) | 否 | 否 |
PUT | UPDATE(改) | 是 | 否 |
DELETE | DELETE(删) | 是 | 否 |
幂等性:对同一REST接口的多次访问,得到的资源状态是相同的。
安全性:对该REST接口访问,不会使服务器端资源的状态发生改变。
@RequestMapping(value = "/user/{id}" ,method=RequestMethod.GET)
public String getUserId(@PathVariable("id") Integer id) {
return "success";
}
同上@RequestMapping注解中的SpringMVC支持路径中的占位符(重点)讲到的一样
因为客户端的请求方法只有GET、POST,不能直接用PUT、DELETE,所以需要一个过滤器来实现
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-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
<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下配置
若配置了
若配置了
浏览器发送到请求会先被DispacherServlet处理,无法处理的交给DefaultServlet处理
<mvc:default-servlet-handler/>
<mvc:annotation-driven>mvc:annotation-driven>
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(配置文件)
<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>
<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>
<mvc:default-servlet-handler/>
<mvc:annotation-driven>mvc:annotation-driven>
<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
<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 Applicationdisplay-name>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>forceEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-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 heretitle>
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 heretitle>
head>
<body>
<div id="app">
<table>
<tr>
<th>idth>
<th>nameth>
<th>sexth>
<th>options(<a th:href="@{/to/add}">adda>)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}}">updatea>
<a @click="getfrom()" th:href="@{'/employee/'+${employee.id}}">deletea>
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 heretitle>
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 heretitle>
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>
将请求体中的内容和控制器方法的形参进行绑定
使用@RequestBody注解json格式的请求参数转换为Java对象
使用条件:
导入Jackson的依赖
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.0version>
dependency>
在springmvc的配置文件中设置
在处理请求的控制器方法的形参位置,直接设置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");
}
使用@ResponseBody注解响应浏览器json格式的数据
使用@ResponseBody注解java对象、map、list集合的请求参数转换为json格式
使用条件:
导入Jackson的依赖
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.0version>
dependency>
在springmvc的配置文件中设置
将需要转换的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;
}
@RestController注解是springmvc提供的一个复合注解,表示在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解
@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
的使用和理解
Spring ResponseEntity 详解:从原理到实践 - 知乎 (zhihu.com)
使用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上传文件步骤:
添加依赖
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.5version>
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>
<mvc:interceptor>
<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两个方法顺序相反。
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">errorprop>
props>
property>
<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";
}
}
在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);
}
}