1.简介
- REST:
Representational State Transfer
,表现层(即前端页面+控制层)资源状态转移(就是一种书写风格)tips:
- 资源是以名词为核心来组织的,即首先关注的是名词。一个资源可以由一个或多个URI来标识,URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互
2.实现
- 四个表示操作方式的动词:
GET、POST、PUT、DELETE
- GET 用来获取资源
- POST 用来新建资源
- PUT 用来更新资源
- DELETE用来删除资源
- REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性:
<body> <a th:href="@{/user}">查询所有用户信息</a> # 超链接默认发送get请求 <a th:href="@{/user/1}">根据用户ID查询信息</a> <form th:action="@{/user}" method="post"> 用户名: <input type="text" name="username"><br> 密 码: <input type="password" name="password"><br> <input type="submit" value="提交"><br> </form> </body>
@Controller public class UserController { /** * 使用RESTful模拟用户资源的CRUD * /user GET 查询所有用户信息 * /user/1 GET 根据用户ID查询信息 * /user POST 添加用户信息 * /user/1 DELETE 根据用户ID删除用户信息 * /user PUT 修改用户信息 */ @RequestMapping(value = "/user", method = RequestMethod.GET) public String getAllUser(){ return "success"; } @RequestMapping(value = "/user/{id}", method = RequestMethod.GET) # 使用占位符接收传来的值 public String getUserById(){ return "success"; } @RequestMapping(value = "/user", method = RequestMethod.POST) public String insertUser(String username, String password){ System.out.println("username:" + username); System.out.println("password:" + password); return "success"; } }
tips:
使用
<a th:href="@{/user}">
后,Thymeleaf
会自动加上上下文信息(即当前项目名称)。如果没有使用的话需要自己通过代码加上,比如在JSP页面中<a href="${pageContext.request.contextPath}/user}">
由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?如果直接把form表单中的请求方式改为put并且把控制器方法中的method改为
RequestMethod.GET
是没有效果的(会变为发送get请求),需要先配置在web.xml
中配置HiddenHttpMethodFilter
:# web.xml <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"> <!--put写为大小写均可,源码中会转为大写--> <input type="hidden" name="_method" value="put"> 用户名: <input type="text" name="username"><br> 密 码: <input type="password" name="password"><br> <input type="submit" value="提交"><br> </form>
@RequestMapping(value = "/user", method = RequestMethod.PUT) public String updateUser(String username, String password){ System.out.println("username:" + username); System.out.println("password:" + password); return "success"; }
SpringMVC
提供了HiddenHttpMethodFilter
将POST
请求转换为DELETE
或PUT
请求
HiddenHttpMethodFilter
处理put
和delete
请求的条件:
- 当前请求的请求方式必须为POST
- 当前请求必须传输请求参数_method
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; // 要求当前请求的请求方式必须为POST if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) { // this.methodParam就是_method String paramValue = request.getParameter(this.methodParam); if (StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH); // ALLOWED_METHODS = // Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), // HttpMethod.DELETE.name(), HttpMethod.PATCH.name())); if (ALLOWED_METHODS.contains(method)) { // 把当前method替换当前request的原始method requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method); } } } filterChain.doFilter((ServletRequest)requestToUse, response); }
在
web.xml
中注册时,必须先注册CharacterEncodingFilter
,再注册HiddenHttpMethodFilter
:
- 在
CharacterEncodingFilter
中通过request.setCharacterEncoding(encoding)
方法设置字
符集的,该方法要求前面不能有任何获取请求参数的操作,而HiddenHttpMethodFilter
恰恰有一个获取请求方式的操作:String paramValue = request.getParameter(this.methodParam)
3.项目中常见问题
添加了静态资源后重新部署还是无法访问:需要使用maven重新打包,这样war包中才会有静态资源,重新部署(让服务器执行war包)采用效果
重新打包后还是访问不了静态资源:因为SpringMVC使用
DispatcherServlet
解析时会把<script type="text/javascript" th:src="@{/static/js/vue.js}">
中的src添加上前后缀,此时需要在SpringMVC.xml
文件中开放对静态资源的访问才能正确解析/static/js/vue.js
为/webapp/static/js/vue.js
(即将当前请求交给默认的servlet
处理)// 开放对静态资源的访问 <mvc:default-servlet-handler/>
- 如果只配置
<mvc:default-servlet-handler/>
不配置<mvc:annotation-driven />
,则项目所有请求(不管是对静态资源的请求还是控制方法的请求)会被默认的servlet
处理