springMVC
springMVC简介
传统的servlet的不足
- 每个请求,都需要定义一个Servlet。虽然可以在service方法中,根据业务标识进行业务分发,但是每个Servlet中的service方法的实现是重复。如果想要对service进行更高层次的封装,就可以解决service的重复代码问题。
- 每个请求的参数,都需要根据request对象,从Map逐一的获取,单调且含量低。将所有的参数,自动封装映射,简化开发。
- 每个Servlet,向客户端返回数据时,需要单独的处理。
- 针对于Servlet在实际使用中的不便,Spring中提供了组件,SpringMVC,更进一步的简化了Servlet的开发。
springMVC的架构
DispatcherServlet
- 核心控制器,本质上就是一个Servlet,处理所有的客户端的请求。根据请求的资源路径,在处理器映射器中查找对应的处理器。
HandlerMapping
处理器映射器,存储所有当前程序中的处理器,如果在处理器映射器中查找不到资源路径,直接返回404。
HandlerAdapter
- 处理器适配器,用于适配各种处理器,调用具体的处理器程序。
Handler
- 具体处理器,开发者实现相应接口或者使用注解声明的程序。用于处理具体的请求。
ViewResolver
视图解析器,根据处理器返回的数据,进行数据处理,将数据处理成相应的格式。
JSP/JSON等等。
完善请求响应流程图
- 用户通过浏览器发送请求到前端控制器DispatcherServlet。
- 前端控制器直接将请求转给处理器映射器HandleMapping。
- 处理器映射器HandleMapping会根据请求,找到负责处理该请求的处理器,并将其封装为处理器执行链HandlerExecutionChina后返回给前端控制器DispatcherServlet。
- 前端控制器DispatcherServlet根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器HandlerAdaptor。
- 处理器适配器HandlerAdaptor调用执行处理器Controller。
- 处理器Controller将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给处理器适配器HandlerAdaptor。
- 处理器适配器直接将结果返回给前端控制器DispatcherServlet。
- 前端控制器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
- 视图解析器ViewResolver将封装了的视图View对象返回给前端控制器DispatcherServlet。
- 前端控制器DispatcherServlet调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
- 前端控制器响应浏览器。
springMVC使用
springMVC配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 开启springmvc 注解 -->
<!-- 开启组件扫描 -->
<context:component-scan base-package="com.*" />
<!-- 开启springmvc 注解驱动 -->
<mvc:annotation-driven />
<!-- 处理静态资源 -->
<mvc:default-servlet-handler/>
<!--配置视图解析器,完成模板的配置-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"/>
<property name="prefix" value="/WEB-INF/"/>
</bean>
</beans>
web.xml中配置springMVC
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>mvc</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>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springMVC的数据绑定
@Controller
public class Controller01 {
// 映射路径 它可以用在方法上 也可以用在类上 映射路径必须要在整个项目中唯一
// @RequestMapping("/register")
// 返回值是String类型,一般表示 返回值的内容是 页面的路径,通过请求转发跳转到该页面上
// 当使用了@ResponseBody这个注解 就变成了把返回值封装成json格式的对象直接响应到浏览器
// @ResponseBody
/**
* @RequestParam 处理 浏览器提交过来的参数的名称 和接受参数的名称不一致的情况
*/
public String register(String name,Integer password,int sex, String hobby,@RequestParam("City") String city){
System.out.println("name = " + name);
System.out.println("password = " + password);
System.out.println("sex = " + sex);
System.out.println("hobby = " + hobby);
System.out.println("city = " + city);
return "/WEB-INF/register.jsp";
}
/**
* 如果表单上的name属性的值和类中的属性的值一致,类型也一致,则,springMVC框架会自动将接收的表单的数据
* 封装到对象中
* @param user
* @return
*/
//@RequestMapping("/register")
public String register2(User user){
System.out.println("user = " + user);
return "/WEB-INF/register.jsp";
}
/**
* springMVC 框架也支持 数据封装到map中,但是必须使用@ReqeustParam注解 搭配使用
* @param map
* @return
*/
// @RequestMapping("/register")
public String register3(@RequestParam Map map ){
map.forEach((x,y)->System.out.printf(x+":" + y));
return "/WEB-INF/register.jsp";
}
/**
* 针对表单提交的数据为一个name 对应多个value的情况,则单独接收可以使用数组接收
* @param hobby
* @return
*/
// @RequestMapping("/register")
public String register4(String[] hobby){
System.out.println(Arrays.toString(hobby));
return "/WEB-INF/register.jsp";
}
/**
* 针对表单提交的数据为一个name 对应多个value的情况,则单独接收可以使用集合接收,但是
* 必须搭配@RequestParam注解一起使用
* @param hobby
* @return
*/
//@RequestMapping("/register")
public String register5(@RequestParam("hobby") List hobby){
for (String s : hobby) {
System.out.println(s);
}
return "/WEB-INF/register.jsp";
}
springMVC的跳转
在SpringMVC中,默认的跳转方式内部转发,,每个URL前面默认有forward:
默认会将方法的返回值当做视图的路径处理。并且,在SpringMVC中,/表示当前项目根目录。如果想要使用重定向,则使用关键字:redirect:/路径。
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class JumpController { @RequestMapping("register") public String forward(){ return "forward:/success.jsp"; // 背后是直接去项目的根目录下面找success.jsp文件 } @RequestMapping("register") public String forward1(){ return "success"; // 背后会使用模板 拼接跳转的路径 /WEB-INFO/success.jsp } /** * 如果想使用重定向的方式跳转到其它页面,那么则使用redirect关键字 * 使用方式: * redirect:绝对路径 * * */ @RequestMapping("/register") public String register7(@RequestParam("hobby") List
hobby){ for (String s : hobby) { System.out.println(s); } return "redirect:/other.jsp"; } }
springMVC支持内置对象
在SpringMVC中,支持为处理器中的方法注入内置的对象,如:HttpServletRequest、HttpServletResponse、HttpSession、Model等。
/** * * @param request * @param resp * @param session * @param model 是springmvc中 推荐使用参数传递的容器 当参数发生覆盖 优先使用model中的参数 * @throws IOException */ @RequestMapping("servletParam.do") public void servletParam(HttpServletRequest request, HttpServletResponse resp, HttpSession session, Model model) throws IOException { String name = request.getParameter("name"); System.out.println(name); System.out.println(request); System.out.println(resp); System.out.println(session); System.out.println(model); resp.sendRedirect("success.jsp"); //return "/success.jsp"; }
springMVC参数传递
在SpringMVC中,可以获取内置HttpServletRequest对象,并且SpringMVC默认使用内部转发,所以可以使用HttpServletRequest进行数据传递,但是SpringMVC推荐使用Model进行数据传递,SpringMVC最终是将URL路径和Model进行结合产生ModelAndView对象。
/** * 演示参数传递问题 * 在springmvc中 默认的跳转是内部转发 * 所以可以使用HttpServletRequest 传递参数 * 但是 springmvc 推荐使用 model 传递参数 并且 model 参数的优先级最高 * * @param request * @param model * @return */ @RequestMapping("param2.do") public String param(HttpServletRequest request,Model model){ model.addAttribute("age",25); model.addAttribute("sex","女"); request.setAttribute("name","韩梅梅"); request.setAttribute("age",18); return "/success.jsp"; }
SpringMVC获取Servlet作用域
代码
import org.springframework.web.context.ContextLoader; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * @Description: 获取Servlet 作用域对象工具类 * HttpServletRequest * HttpSession * ServletContext */ public class WebScopeUtil { /** * 获取当前 HttpServletRequest 对象 * @return */ public static HttpServletRequest getRequest(){ ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); return requestAttributes.getRequest(); } /** * 获取当前请求绑定的session * @return */ public static HttpSession getSession(){ return getRequest().getSession(); } /** * 获取全局容器对象 * @return */ public static ServletContext getContext(){ //getRequest().getServletContext(); // ServletContext 的生命周期 是早于 HttpServletRequest //所以不能通过 HttpServletRequest 获取ServletContext 可能发生 NullpointException return ContextLoader.getCurrentWebApplicationContext().getServletContext(); } }
springMVC内置的编码过滤器
代码
<!-- 编码过滤器 --> <filter> <filter-name>charsetFilter</filter-name> <!-- 配置内置的编码过滤器 --> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!-- 为编码过滤器指定编码 --> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>charsetFilter</filter-name> <!-- 只对springmvc处理的请求进行编码过滤 --> <url-pattern>/*</url-pattern> </filter-mapping>
springMVC响应JSON
xml配置的形式
XML配置形式,是修改了默认结果处理,全局生效的。使用注解@ResponseBody,标识该方法返回的内容不是URL地址,而是一个消息,使用输出对象输出给客户端。
@RequestMapping
name : 方法映射名称
value/path : 方法访问路径
method : 支持的请求的方法类型:
GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE
params : 请求必须有的参数
headers : 请求必须有的头信息
consumes : 指定请求的数据格式类型 : 普通文本、表单格式、JSON
produces : 指定返回数据的格式类型 :JSON 、HTML
注解
SpringMVC中,有内置的转换器,但是SpringMVC内置的转换器需要相关jar包,需要jackson的jar包。只需要导入jar包后,使用**@ResponseBody标识返回的数据是消息即可。SpringMVC自动将返回数据当做JSON字符串处理,并且消息按照UTF-8进行编码。如果@ResponseBody放在类上,类中所有的方法都返回的是消息,不是视图资源。**
注意: @RestController
是 @ResponseBody, @Controller 结合,标识该类是一个处理器,并且处理器中所有的方法都返回的是消息。
文件的上传和下载
文件上传
导包
<!-- 文件上传相关依赖jar --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency>
配置文件上传的解析器
<!-- 文件上传的解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
处理器
@Controller @RequestMapping("/fileUpload") public class FileUploadController { @RequestMapping("") @ResponseBody // MultipartFile 从servlet 3.0 以后支持文件上传 参数的名称 必须和 表单中的上传控件的名称 保持一致 public String upload(MultipartFile file){ /** * 文件上传考虑的问题: * 文件上传的路径的问题 * 上传文件的大小问题 * 上传文件的类型 * 上传文件的名称设置 * * 问题解决方案: * 文件上传的路径的问题 (1.项目的根目录下面(使用少),2.使用第三方的图片服务器(阿里,七牛云...)) * 上传文件的大小问题 通过上传的文件可以获取到文件的真实大小,可以达到限制的目的 * 上传文件的类型问题 通过上传的文件可以获取到文件的类型。进而进行判断 * 上传文件的名称问题 通过时间戳 或者 UUID 来随机生成文件的新的名称达到唯一的目的 * */ String originalFilename = file.getOriginalFilename(); System.out.println("文件的原始名称 = " + originalFilename); System.out.println("文件的大小 (字节)= " + file.getSize()); System.out.println("文件的类型 = " + file.getContentType()); try { File newFile = new File("D://" + file.getOriginalFilename()); Font font = new Font("微软雅黑", Font.BOLD, 15); // 字体的属性设置 // 文件上传的方法 ImgUtil.pressText(file.getInputStream(), new FileOutputStream(newFile), "我是水印", Color.RED, font, 1, 1, 0.5f); }catch (Exception e){ e.printStackTrace(); } return "文件上传成功"; } }
文件下载
方法一
文件下载的本质,就是获取服务器的文件数据信息,使用字节流将数据传递给客户端。
使用输入流,将磁盘文件读到内存中。
使用网络输出流,将数据输出给客户端。
@Controller @RequestMapping("/download") public class DownloadController { @RequestMapping("") public void download(String fileName, HttpServletResponse response) throws Exception { // 准备要下载的文件 File file = new File("d://" + fileName); //设置响应类型 通知浏览器 不要打开 response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 通过设置头信息 不让浏览器把图片的名称 后缀名进行修改 String name = URLEncoder.encode(fileName, "UTF-8"); System.out.println("编码后的名字:"+name); response.setHeader("Content-Disposition", "attachment; filename="+name); // 把下载的文件转成流对象 FileInputStream fileInputStream = new FileInputStream(file); // 获取输出流 ServletOutputStream outputStream = response.getOutputStream(); int len = 0; byte[] buffer = new byte[1024]; while ((len=fileInputStream.read(buffer))!=-1){ outputStream.write(buffer,0,len); outputStream.flush(); } outputStream.close(); fileInputStream.close(); } /** * 现实开发中,注意点: * 1. 下载需要限制 * 2. 下载的源头是服务器地址 (文件上传的操作 * (把文件上传到云服务器以后,然后云服务器会返回一个url地址(图片在云服务器上的真实地址), * 后 台程序拿到图片的真实地址和图片的源文件名称 一同 存入到数据库中) * */ }
方法二
springMVC中为了简化文件的下载,封装了实体类:ResponseEntity,可以将文件数据封装在ResponseEntity中。
package com.abc.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URLEncoder; /** * @Description: 文件下载示例 */ @Controller @RequestMapping("download") public class DownLoadController { @RequestMapping("download2.do") public ResponseEntity
download() throws Exception { File file = new File("E:\\猪图片.jpg");//本地磁盘文件 //使用输入流 将文件读入内存中 FileInputStream fis = new FileInputStream(file); // 找参照物 将程序运行的内存当做参照物 //文件的大小 long length = file.length(); //创建一个和文件一样大小的字节数组 一次性将数据读入到内存中 如果文件量过大,请求比较频繁 存在 崩溃的风险 byte[] fileByte = new byte[(int) length];//一个G 的 byte 数组 64 G 65个人下载 1分钟 //一次性将文件数据读入到数组中 fis.read(fileByte); // springmvc 中封装的 响应实体 : //设置响应码 //设置响应的数据头信息 //设置响应数据 HttpHeaders headers = new HttpHeaders(); //响应头信息 //设置响应的数据为流数据 告诉浏览器 不要解析 headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); //设置下载的文件的名称 中文字符串要进行编码 headers.setContentDispositionFormData("filename","猪图片.jpg"); ResponseEntity responseEntity = new ResponseEntity(fileByte,headers, HttpStatus.OK); return responseEntity; } }
springMVC拦截器
使用拦截器
创建类实现HandlerInteceptor接口
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @Description: 自定义拦截器 */ public class MyInterceptor implements HandlerInterceptor { /** * 在执行具体的Handler中的方法前执行 * @param request 当前的请求对象 * @param response 当前的响应对象 * @param handler 具体的处理器中将要执行的方法 * @return boolean 如果 返回 true 则执行Handler中的方法 false 则 不执行handler中的方法 * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器中preHandle 方法"); return true; } /** * 在具体的Handler中的方法执行完成 但是没有做具体的视图解析操作 * @param request 当前 请求对象 * @param response 当前响应对象 * @param handler 具体的处理器中将要执行的方法 * @param modelAndView 具体的处理器中将要执行的方法 返回的结果 * @throws Exception */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器中postHandle 方法"); //在具体的解析之前 修改视图模型中数据 modelAndView.addObject("name","韩梅梅"); } /** * 完成了视图解析后 整个方法执行完成调用的方法 在finally中调用 或者出现异常也会调用 * @param request 当前请求对象 * @param response 当前响应对象 * @param handler 具体的处理器中将要执行的方法 * @param ex 具体的处理器中抛出的异常 * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("我是拦截器中afterCompletion 方法"); System.out.println(ex.getMessage()); request.setAttribute("msg","网管去火星了!"); request.getRequestDispatcher("/500.jsp").forward(request,response); } }
配置拦截器
<?xml version="1.0" encoding="UTF-8"?> <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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启组件扫描 --> <!-- 扫描所有处理器 放入到处理器映射器中 --> <context:component-scan base-package="com.bjpowernode.controller" /> <!-- 开启 mvc注解 --> <mvc:annotation-driven></mvc:annotation-driven> <!-- 文件上传的解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <!--<property name="maxUploadSize" value="1"></property>--> </bean> <!-- 配置springmvc的拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 拦截器的资源路径 /** 拦截所有 ** 表示多层目录 --> <mvc:mapping path="/**"/> <!-- 不拦截的资源路径 --> <mvc:exclude-mapping path="/user/page.do"/> <!-- 自定义的拦截器 --> <bean id="myInterceptor" class="com.bjpowernode.interceptor.MyInterceptor" /> </mvc:interceptor> </mvc:interceptors> </beans>
Interceptor和Filter的区别
- Filter是Java Web的规范,拦截的是请求,任何JavaWeb项目都可以有Filter,但是Interceptor是SpringMVC提供的一套规范HandlerInterceptor,只适用SpringMVC自身,并且只能对DispatherServlet处理器的请求生效,拦截的方法。从范围上说,任何JavaWeb项目都有Filter,但是未必有Interceptor。
同一异常处理器
在spring中,相对完善的异常处理器机制,spring可以自己定义处理异常的规则,这种处理异常规则的程序,就被称之为异常处理器。其实,异常处理器就是对controller的增强,因为异常是向上抛,controller调用service,service调用mapper,controller属于最上层,所以最终异常都会汇集到controller。因此,spring提供了@ControllerAdvice注解,表示对controller增强类。并且还提供了@ExceptionHandler这个注解,当发生异常时,该注解修饰的方法就会执行
在实际开发中,异常主要分为两类:
- 系统异常,JDK中定义的异常
- 业务异常,开发者自己定义的异常
一般是将系统异常转化为业务异常,开发者只处理业务异常。使用try…catch…将代码包裹起来,在catch中抛出自定义的异常,这种方案就是将系统异常转化为业务异常。因为很多数据操作,事务需要异常进行数据回滚。
例子
// 当密码出现问题的时候 ,使用 public class MyPasswordException extends RuntimeException{ public MyPasswordException(String msg){ super(msg); } } @Repository public class UserMapper { public boolean select(String name, String pwd) { int i = 1/0; if (name.equals("root")&&pwd.equals("123")) { return true; } return false; } } @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; // @Override // public boolean login(String name, String pwd) { // // if (name==null || name.equals("")) { // throw new RuntimeException("账号不能为空"); // } // // if (pwd==null || pwd.equals("")) { // throw new RuntimeException("密码不能为空"); // } // // try { // return userMapper.select(name,pwd); // }catch (Exception e){ // e.printStackTrace(); // return false; // } // // } @Override public void login(String name, String pwd) { if (name==null || name.equals("")) { throw new MyAccountException("账号不能为空"); } if (pwd==null || pwd.equals("")) { throw new MyPasswordException("密码不能为空"); } boolean result = userMapper.select(name,pwd); if (!result){ throw new MyLogicException("账号或者密码错误"); } } } public interface UserService { void login(String name, String pwd); } // 统一异常的处理类 @ControllerAdvice public class MyControllerAdvice { @ExceptionHandler(MyAccountException.class) @ResponseBody public String accountException(MyAccountException exception){ return exception.getMessage(); } @ExceptionHandler(MyPasswordException.class) public String pwdException(MyPasswordException exception){ return "500"; } @ExceptionHandler(MyLogicException.class) public String logicException(MyLogicException exception){ return "redirect:/login.html"; } @ExceptionHandler(RuntimeException.class) @ResponseBody public String runtimeException(RuntimeException exception){ return "程序崩溃"; } } @Controller @RequestMapping("/loginUser") public class LoginController { @Autowired private UserService userService; @RequestMapping("") @ResponseBody public String login(String name,String pwd) { userService.login(name,pwd); return "登录失败"; } }
Restful风格
Http协议设计的初衷
HTTP协议在设计时,期望使用一个URL表示一个资源。然后,根据不同的动作:GET、POST、PUT、DELETE等等表示对一个资源的各种操作。
如:
获取这个资源就使用GET,
修改这个资源PUT,
删除这个资源用DELETE,
创建这个资源使用POST。
但是在实际使用中,多个URL表示一个资源,例如:新增用户: addUser.do,修改用户:updateUser.do,删除用户:deleteUser.do,查询一个用户:getUser.do。这时候,出现一个资源存在多个URL。在一定程度声,违背了HTTP协议的设计初衷,并且命名也是个问题。
Restful设计思想
使用一个URL表示一种资源
客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源
通过操作资源的表现形式来操作资源
在SpringMVC中使用Restful
- SpringMVC也支持Restful风格,但是目前存在一些问题。主要不是很好支持PUT请求,没有办法获取到PUT请求的数据。
将DispatherServlet的映射地址改为
由于将DispatherServlet的映射路径,改为了/,则所有的请求都由DispatherServlet处理,静态的资源文件不在处理器映射器中,会出现404。并拦截器拦截DispatherServlet中调用Handler中的方法,改为/,则所有的请求都会被拦截。
则需要在SpringMVC的核心配置文件中,新增启用默认的Servlet的处理器。
<!-- 启用默认Servlet --> <mvc:default-servlet-handler/>
并且注意,配置拦截器时,将静态资源不进行拦截,要排除:
<mvc:exclude-mapping path="/resouces/**"/>
配置处理PUT请求的拦截器
代码
<!-- 处理put请求的拦截器 --> <filter> <filter-name>restful</filter-name> <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class> </filter> <filter-mapping> <filter-name>restful</filter-name> <servlet-name>springmvc</servlet-name> </filter-mapping>
处理器代码
代码
package com.abc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @Controller @RequestMapping("user") @ResponseBody public class UserController { // @RequestMapping(method = RequestMethod.GET) // //@GetMapping // public Object get(Integer id){ // System.out.println("get请求"); // Map
data = new HashMap<>(); // data.put("code",200); // data.put("msg","get请求"); // return data; // } @GetMapping("{id}/{name}") //后台的获取方式 使用 {} 进行包裹 并且 在方法参数中 使用@PathVariable // 这种将参数拼接在URL上的方式 只支持 GET 请求和 DELETE请求 public Object get1(@PathVariable("id") Integer id,@PathVariable("name") String name){ System.out.println("get请求"); System.out.println(id); System.out.println(name); Map data = new HashMap<>(); data.put("code",200); data.put("msg","get请求"); return data; } //@RequestMapping(method = RequestMethod.PUT) @PutMapping public Object put(Integer id){ System.out.println("PUT请求"); Map data = new HashMap<>(); data.put("code",200); data.put("msg","PUT请求"); return data; } @RequestMapping(method = RequestMethod.POST) //@PostMapping public Object post(Integer id){ System.out.println("post请求"); Map data = new HashMap<>(); data.put("code",200); data.put("msg","post请求"); return data; } @RequestMapping(method = RequestMethod.DELETE) @DeleteMapping public Object delete(Integer id){ System.out.println("delete请求"); Map data = new HashMap<>(); data.put("code",200); data.put("msg","delete请求"); return data; } }
页面代码
代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="btn1">get</button> <button id="btn2">put</button> <button id="btn3">delete</button> <button id="btn4">post</button> <button id="btn5">get-1111</button> <script src="resources/jquery.js"></script> <script> $("#btn1").click(function () { $.get("user",{id:1001},function (rs) { console.log(rs); }) }); $("#btn2").click(function () { $.ajax({ url:"user", type:"PUT", param:{id:1001}, success:function (rs) { console.log(rs); } }) }); $("#btn3").click(function () { $.ajax({ url:"user", type:"DELETE", param:{id:1001}, success:function (rs) { console.log(rs); } }) }); $("#btn4").click(function () { $.post("user",{id:1001},function (rs) { console.log(rs); }) }); $("#btn5").click(function () { //将参数 拼接在URL上面 $.get("user/11111/lucy",function (rs) { console.log(rs); }) }); </script> </body> </html>