Spring官网: https://spring.io/
SpringMVC:控制层框架【接收请求,响应请求】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E2IwLvw9-1626832705315)(img\1598355971112.png)]
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.17.RELEASEversion>
dependency>
dependencies>
<build>
<finalName>gp_springmvc_01_hellofinalName>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
<configuration>
<port>8082port>
<path>/path>
<uriEncoding>utf-8uriEncoding>
configuration>
plugin>
plugins>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
beans>
<web-app>
<display-name>Archetype Created Web Applicationdisplay-name>
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-mvc.xmlparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
package com.gupaoedu;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 让每一个人的职业生涯不留遗憾
*
* @author 波波老师【咕泡学院】
*/
public class UserController implements Controller {
/**
* 处理请求的方法
* @param httpServletRequest
* @param httpServletResponse
* @return
* @throws Exception
*/
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest
, HttpServletResponse httpServletResponse) throws Exception {
System.out.println("controller 执行了....");
ModelAndView view = new ModelAndView();
view.setViewName("/index.jsp");
return view;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<bean class="com.gupaoedu.UserController" name="/user"/>
beans>
原理分析:
DispatchServlet
init:IoC容器的初始化操作
初始化SpringMVC的九大组件
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
// 加载我们在配置文件中添加的处理器映射器
this.initHandlerMappings(context);
// 加载我们在配置文件中添加的处理器适配器
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<context:component-scan base-package="com.gupaoedu.controller" />
<mvc:annotation-driven />
beans>
package com.gupaoedu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 让每一个人的职业生涯不留遗憾
*
* @author 波波老师【咕泡学院】
*/
@Controller // 将UserController对象交给IoC容器管理
@RequestMapping("/user") // 类头部的可以省略
public class UserController {
/**
* 具体处理请求的方法 【头部的mapping+方法的mapping】
* http://localhost:8082/user/query
* @return
*/
@RequestMapping("/query")
public String query(){
System.out.println("query ..... ");
return "/index.jsp";
}
@RequestMapping("/save")
public String add(){
System.out.println("save ..... ");
return "/index.jsp";
}
@RequestMapping("/delete")
public String delete(){
System.out.println("delete ..... ");
return "/index.jsp";
}
@RequestMapping("/update")
public String update(){
System.out.println("update ..... ");
return "/index.jsp";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uAcrpWac-1626832705316)(img\1598364125831.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-17UGz0Gm-1626832705318)(img\1598364984600.png)]
我们可以在处理方法的最后返回一个要跳转的页面地址”/“不要漏了
@RequestMapping("/query")
public String query(){
System.out.println("query ..... ");
return "/index.jsp";
}
如果用户提交了请求后服务端不需要给客户端一个响应,那么我们可以指定返回类型为void
同时在方法头部添加@ResponseBody
注解即可
@RequestMapping("/save")
@ResponseBody
public void add(){
System.out.println("save ..... ");
}
我们也可以直接返回一个ModelAndView对象
@RequestMapping("/delete")
public ModelAndView delete(){
System.out.println("delete ..... ");
ModelAndView mm = new ModelAndView();
mm.setViewName("/index.jsp");
return mm;
}
有些情况下重定向跳转也是我们开发中必须使用的形式
@RequestMapping("/update")
public String update(){
System.out.println("update ..... ");
return "redirect:/user/query";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lL4j6K7e-1626832705319)(img\1598424336053.png)]
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name="suffix" value=".jsp"/>
<property name="prefix" value="/" />
bean>
那这样的话响应的页面就会自动添加对应的前后缀信息
@RequestMapping("/query")
public String query(){
System.out.println("query ..... ");
return "index";
}
仅仅只需要在方法的形参中声明这两个变量即可~
@RequestMapping("/fun1")
public void fun1(HttpServletRequest request
,HttpServletResponse response) throws Exception {
// response.sendRedirect("/index.jsp");
System.out.println("fun1 ...");
request.getRequestDispatcher("/index.jsp").forward(request,response);
}
直接在形参中声明要接收的数据,默认情况下形参必须和传过来的数据参数名一致
@RequestMapping("/query")
public String query(@RequestParam(value = "ids",required = true,defaultValue = "123") Integer id, String name){
System.out.println("query ..... " + id + ":" + name);
return "/index.jsp";
}
如果传递过来的数据比较多,那么我们可以通过一个自定义的对象来接收
@RequestMapping("/save")
public String add(User user){
System.out.println("save ..... " + user);
return "/index.jsp";
}
如果有多个名称相同的数据提交,我们可以使用数组的方式来接收
@RequestMapping("/delete")
public String delete(String[] loves){
System.out.println("delete ..... ");
if(loves !=null){
for(String l : loves){
System.out.println(l);
}
}
return "/index.jsp";
}
注意:在形参中我们不能够通过集合的方式来获取传递的参数
在自定义对象中可以使用集合获取数组的形式来接收请求的参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gdoiMsqU-1626832705320)(img\1598428934188.png)]
有时候客户端传递过来特殊类型的数据,SpringMVC中提供的默认的转换器不能支持该转换,此时我们就需要自定义转换器
package com.gupaoedu.convert;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 让每一个人的职业生涯不留遗憾
* 自定义的类型转换器
* @author 波波老师【咕泡学院】
*/
public class DateConvert implements Converter<String,Date> {
@Override
public Date convert(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
return sdf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
配置文件中注册
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<context:component-scan base-package="com.gupaoedu.controller" />
<mvc:annotation-driven conversion-service="formattingConversionServiceFactoryBean"/>
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean"
id="formattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.gupaoedu.convert.DateConvert"/>
set>
property>
bean>
beans>
@RequestMapping("/query")
public ModelAndView query(){
System.out.println("query ..... ");
ModelAndView mm = new ModelAndView();
mm.setViewName("/user.jsp");
mm.addObject("msg","msg.....");
return mm;
}
然后在jsp页面中通过EL表达式获取传递的信息
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2020/8/26
Time: 16:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Titletitle>
head>
<body>
hello<br>
${msg}
body>
html>
ModelAndView使用起来稍微有点复杂,我们可以通过Map来简化操作
@RequestMapping("/save")
public String add(Map<String,Object> map){
System.out.println("save ..... ");
map.put("msg","map ...msg");
return "/index.jsp";
}
@RequestMapping("/delete")
public String delete(Model model){
System.out.println("delete ..... ");
model.addAttribute("msg","model ...msg");
return "/index.jsp";
}
@RequestMapping("/update")
public String update(ModelMap mm){
System.out.println("update ..... ");
mm.put("msg","ModelMap ... msg");
return "/index.jsp";
}
前面介绍的多种方式的数据都是会被保存在request作用域中,如果我们同时需要将数据保存在Session对象中,我们只需要在类的头部添加一个@SessionAttributes注解即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1gHAZTzz-1626832705321)(img\1598431973792.png)]
<filter>
<filter-name>encodeFiletrfilter-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>forceRequestEncodingparam-name>
<param-value>trueparam-value>
init-param>
<init-param>
<param-name>forceResponseEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodeFiletrfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.4version>
dependency>
提交的方式必须是post
方式,提交的数据的类型必须是二进制文件
<html>
<body>
<h2>Hello World!h2>
<form action="/user/save" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="username"><br>
头像:<input type="file" name="headImg"><br>
<input type="submit" value="提交">
form>
body>
html>
提交的文件我们可以通过 MultipartFile
类型来接收
@RequestMapping("/save")
public String add(MultipartFile headImg,String username) throws IOException {
System.out.println(username);
System.out.println("文件名称:" + headImg.getOriginalFilename());
headImg.transferTo(new File("d:/" + headImg.getOriginalFilename()));
return "/index.jsp";
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<context:component-scan base-package="com.gupaoedu.controller" />
<mvc:annotation-driven />
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<property name="maxUploadSize">
<value>5242880value>
property>
bean>
beans>
@RequestMapping("/download")
public void download(HttpServletRequest request,
HttpServletResponse response){
File file = new File("d://1.png");
// 设置响应的头和客户端保存文件名
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition","attchement;filename=" + file.getName());
try {
// 打开本地文件流
InputStream in = new FileInputStream(file);
// 激活下载的流
ServletOutputStream out = response.getOutputStream();
byte[] b = new byte[1024];
int num = 0;
while ((num = in.read(b)) != -1){
out.write(b,0,num);
}
out.close();
in.close();
}catch (Exception e){
e.printStackTrace();
}
}
默认的情况下在SpringMVC中只能访问jsp页面,其他的都会被DispatchServlet
拦截,原因是DispatchServlet
配置的时候用的/
覆盖掉了default
servlet所做的工作,所以我们只需要重新制定即可
<filter-mapping>
<filter-name>encodeFiletrfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.pngurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5IaWwzRJ-1626832705322)(img\1598443334557.png)]
第二种方式就是在SpringMVC中指定映射的规则
<mvc:resources mapping="/img/**" location="/img/" />
最早的校验,就是服务端校验。早期的网站,用户输入一个邮箱地址,校验邮箱地址需要将地址发送到服务端,服务端进行校验,校验成功后,给前端一个响应。有了JavaScript,校验工作可以放在前端去执行。那么为什么还需要服务端校验呢? 因为前端传来的数据不可信。前端很容易获取都后端的数据接口,如果有人绕过页面,就会出现非法数据,所以服务端也要数据校验,总的来说:
1.前端校验要做,目的是为了提高用户体验
2.后端校验也要做,目的是为了数据安全
SpringMVC本身是没有提供校验框架的,我们需要使用Hibernate提供的校验框架
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>5.3.0.Alpha1version>
dependency>
在配置文件中注册对应的校验框架
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<context:component-scan base-package="com.gupaoedu.controller" />
<mvc:annotation-driven validator="localValidatorFactoryBean" />
<mvc:resources mapping="/img/**" location="/img/" />
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<property name="maxUploadSize">
<value>5242880value>
property>
bean>
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" id="localValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
<property name="validationMessageSource" ref="messageSource" />
bean>
<bean class="org.springframework.context.support.ReloadableResourceBundleMessageSource" id="messageSource">
<property name="basename" value="classpath:volidata.properties"/>
<property name="fileEncodings" value="utf-8"/>
<property name="cacheSeconds" value="120"/>
bean>
beans>
验证规则
注解 | 说明 |
---|---|
@Null | 被注解的元素必须为 null |
@NotNull | 被注解的元素必须不为 null |
@AssertTrue | 被注解的元素必须为 true |
@AssertFalse | 被注解的元素必须为 false |
@Min(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max=, min=) | 被注解的元素的大小必须在指定的范围内 |
@Digits (integer, fraction) | 被注解的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注解的元素必须是一个过去的日期 |
@Future | 被注解的元素必须是一个将来的日期 |
@Pattern(regex=,flag=) | 被注解的元素必须符合指定的正则表达式 |
@NotBlank(message =) | 验证字符串非null,且长度必须大于0 |
被注解的元素必须是电子邮箱地址 | |
@Length(min=,max=) | 被注解的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注解的字符串的必须非空 |
@Range(min=,max=,message=) | 被注解的元素必须在合适的范围内 |
在自定义的对象中指定验证规则
package com.gupaoedu.pojo;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
/**
* 让每一个人的职业生涯不留遗憾
*
* @author 波波老师【咕泡学院】
*/
public class User {
private Integer id;
@NotNull(message = "账号不能为空")
@Length(message = "账号的长度必须在3~6位" ,max = 6,min = 3)
private String userName;
@Max(message = "age最大值是120",value = 120)
@Min(message = "age必须大于0" ,value = 0)
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
在控制层中使用校验规则
@RequestMapping("/save")
public String add(@Validated User user, BindingResult br) throws IOException {
System.out.println("save ....");
List<ObjectError> allErrors = br.getAllErrors();
for (ObjectError error:allErrors){
System.out.println(error.getDefaultMessage());
}
return "/index.jsp";
}
分组验证解决的是不同的同一个POJO对象在不同的场景用适用不同的验证规则
定义分组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-exU05hPj-1626832705323)(img\1598446901586.png)]
验证规则和分组绑定
package com.gupaoedu.pojo;
import com.gupaoedu.group.GroupInterface1;
import com.gupaoedu.group.GroupInterface2;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
/**
* 让每一个人的职业生涯不留遗憾
*
* @author 波波老师【咕泡学院】
*/
public class User {
@NotBlank(message = "ID不能为空" ,groups = {GroupInterface1.class})
private Integer id;
@NotBlank(message = "{user.username.empty}" ,groups = {GroupInterface1.class,GroupInterface2.class})
@Length(message = "账号的长度必须在3~6位" ,max = 6,min = 3,groups = {GroupInterface1.class,GroupInterface2.class})
private String userName;
@Max(message = "age最大值是120",value = 120,groups = {GroupInterface1.class,GroupInterface2.class})
@Min(message = "age必须大于0" ,value = 0,groups = {GroupInterface1.class,GroupInterface2.class})
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
应用
@RequestMapping("/save")
public String add(@Validated({GroupInterface2.class}) User user, BindingResult br, Model model) throws IOException {
System.out.println("save ....");
List<ObjectError> allErrors = br.getAllErrors();
for (ObjectError error:allErrors){
System.out.println(error.getDefaultMessage());
}
return "/index.jsp";
}
@RequestMapping("/update")
public String update(@Validated({GroupInterface1.class}) User user, BindingResult br, Model model) throws IOException {
System.out.println("update ....");
List<ObjectError> allErrors = br.getAllErrors();
for (ObjectError error:allErrors){
System.out.println(error.getDefaultMessage());
}
return "/index.jsp";
}
Jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>2.9.9version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.9version>
dependency>
响应数据为JSON格式的信息
@RequestMapping("/query")
@ResponseBody
public List<User> query(){
System.out.println("query ..... ");
return Arrays.asList(new User(1,"zhangsan1",18)
,new User(2,"zhangsan2",19)
,new User(3,"zhangsan3",12));
}
接受数据为JSON数据,提交的类型必须是post方式提交
链接:https://pan.baidu.com/s/19bNyGWc5LVOX5HgIRKFCEA
提取码:bobo
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2020/8/26
Time: 21:21
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
<script type="text/javascript" src="js/jquery.min.js">script>
head>
<body>
<input type="button" value="提交JSON数据" onclick="fun1();">
<script type="text/javascript">
function fun1(){
$.ajax({
type: 'POST',
url: "/user/save",
contentType: "application/json",//如果想以json格式把数据提交到后台的话,这个必须有,否则只会当做表单提交
data: JSON.stringify({"userName":"sam","age":"12"}),//JSON.stringify()必须有,否则只会当做表单的格式提交
dataType: "json",//期待返回的数据类型
success: function(data){
alert("success:"+data);
},
error:function(data){
alert("error"+data);
}
});
}
script>
body>
html>
Restful是一种设计风格,是一个规范,不是一个技术。
提交方式 | 地址 | 说明 |
---|---|---|
GET(查) | http://localhost:8080/book/1 | 查询id为1的书 |
POST(增) | http://localhost:8080/book/1 | 添加一本书,书的id为1 |
DELETE(删) | http://localhost:8080/book/1 | 删除id为1的书 |
PUT(改) | http://localhost:8080/book/1 | 修改id为1的书 |
控制器处理
package com.gupaoedu.controller;
import com.gupaoedu.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
/**
* 让每一个人的职业生涯不留遗憾
*
* @author 波波老师【咕泡学院】
*/
/*@Controller // 将UserController对象交给IoC容器管理
//@RequestMapping("/user") // 类头部的可以省略
@ResponseBody*/
@RestController
public class UserController {
/**
* 具体处理请求的方法 【头部的mapping+方法的mapping】
* http://localhost:8082/user/query
* @return
*/
@GetMapping("/user/{id}/{name}")
public List<User> query(@PathVariable Integer id,@PathVariable String name){
System.out.println("query ..... " + id + " " + name);
return Arrays.asList(new User(1,"zhangsan1",18)
,new User(2,"zhangsan2",19)
,new User(3,"zhangsan3",12));
}
@PostMapping("/user")
public String add(@RequestBody User user){
System.out.println("save ..... " + user);
return "/index.jsp";
}
@DeleteMapping("/user")
public String delete(){
System.out.println("delete ..... ");
return "/index.jsp";
}
@PutMapping("/user")
public String update(){
System.out.println("update ..... ");
return "/index.jsp";
}
}
http://localhost:8082/user/666/lisi
定义自定义的拦截器
@Service
public class UserTokenInterceptor implements HandlerInterceptor {
@Autowired
private SysusertokenMapper sysusertokenMapper;
@Autowired
private SysloginuserMapper sysloginuserMapper;
@Autowired
private SysuserMapper sysuserMapper;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 在请求处理之前进行调用(Controller方法调用之前),返回true才会继续往下执行,返回false取消当前请求
boolean isAccess = false;
String tokenCode = request.getHeader("Token");
if (tokenCode != null && !"".equals(tokenCode)) {
//查询未过期的
Sysusertoken sysusertoken = sysusertokenMapper.selectByTokenCode(tokenCode);
if (sysusertoken != null) {
Sysloginuser sysloginuser = sysloginuserMapper.selectByPrimaryKey(sysusertoken.getLoginid());
Sysuser sysuser = sysuserMapper.selectByPrimaryKey(sysloginuser.getUserid());
request.getSession().setAttribute("user",sysuser);
request.getSession().setAttribute("token",tokenCode);
isAccess = true;
}
}
return isAccess;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
2.新建一个配置类来管理拦截器,将你之前新建的拦截器注入进来
addPathPatterns("/**")是拦截所有请求
excludePathPatterns("","",…)配置无需拦截的请求
package com.gcexe.monitor.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Component
public class UserTokenAppConfigurer extends WebMvcConfigurationSupport{
@Autowired
private UserTokenInterceptor userTokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 多个拦截器组成一个拦截器链
// addPathPatterns 用于添加拦截规则
// excludePathPatterns 用户排除拦截
registry.addInterceptor(userTokenInterceptor).addPathPatterns("/**")
.excludePathPatterns("/account/login","/account/register");
super.addInterceptors(registry);
}
}
注册拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.gupaoedu.interceptor.MyInterceptor"/>
mvc:interceptor>
mvc:interceptors>
二、使用servlet的filter过滤器
新建一个类实现javax.servlet.Filter接口,通过@WebFilter注解来配置要拦截的请求,doFilter方法是要进行的操作。
package com.gcexe.monitor.filter;
import java.io.IOException;
import java.util.Arrays;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.gcexe.monitor.persistence.dao.SysloginuserMapper;
import com.gcexe.monitor.persistence.dao.SysuserMapper;
import com.gcexe.monitor.persistence.dao.SysusertokenMapper;
import com.gcexe.monitor.persistence.entity.Sysloginuser;
import com.gcexe.monitor.persistence.entity.Sysuser;
import com.gcexe.monitor.persistence.entity.Sysusertoken;
@Component
@WebFilter(urlPatterns = "/**", filterName = "monitorFilter")
public class TokenAuthorFilter implements Filter {
@Autowired
private SysusertokenMapper sysusertokenMapper;
@Autowired
private SysloginuserMapper sysloginuserMapper;
@Autowired
private SysuserMapper sysuserMapper;
private static final String[] excludePathPatterns = { "/monitor/account/login", "/monitor/account/register" };
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
// 在请求处理之前进行调用(Controller方法调用之前),返回true才会继续往下执行,返回false取消当前请求
boolean isFilter = false;
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// 不拦截登陆和注册
String url = request.getRequestURI();
if (Arrays.asList(excludePathPatterns).contains(url)) {
chain.doFilter(request, response);
return;
}
String tokenCode = request.getHeader("Token");
if (tokenCode != null && !"".equals(tokenCode)) {
// 查询未过期的
Sysusertoken sysusertoken = sysusertokenMapper.selectByTokenCode(tokenCode);
if (sysusertoken != null) {
Sysloginuser sysloginuser = sysloginuserMapper.selectByPrimaryKey(sysusertoken.getLoginid());
Sysuser sysuser = sysuserMapper.selectByPrimaryKey(sysloginuser.getUserid());
request.getSession().setAttribute("user", sysuser);
request.getSession().setAttribute("token", tokenCode);
isFilter = true;
}
}
if (isFilter) {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
执行chain.doFilter(request,response)方法类似于上面的返回true,让程序继续往下执行
可以自己配置返回内容,无需拦截的请求,我这里是定义了一个数组,自行判断,对应地址直接执行chain.doFilter(reuqest.response),同样注意加上@Component注解
三、过滤器和拦截器区别
主要区别如下:
1、拦截器主要是基于java的反射机制的,而过滤器是基于函数回调
2、拦截器不依赖于servlet容器,过滤器依赖于servlet容器
3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问
5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次