1、restful介绍:
我们在 Web 应用中处理来自客户端的请求时,通常只考虑 GET 和 POST 这两种 HTTP 请求方法。实际上,HTTP 还有 HEAD、PUT、DELETE 等请求方法。而在 REST 架构中,用不同的 HTTP 请求方法来处理对资源的 CRUD(创建、读取、更新和删除)操作
/blog/1 HTTP GET => 得到id = 1的blog
/blog/1 HTTP DELETE => 删除 id = 1的blog
/blog/1 HTTP PUT => 更新id = 1的blog
/blog HTTP POST => 新增BLOG
问题:
1.如何在java构造没有扩展名的RESTful url,如 /forms/1,而不是 /forms/1.do
2.浏览器的form标签不支持提交delete,put请求,如何曲线解决
3.springmvc rest 实现:springmvc的resturl是通过@RequestMapping 及@PathVariable annotation提供的,通过如@RequestMapping(value="/blog /{id}",method=RequestMethod.DELETE)即可处理/blog/1 的delete请求.
2、实例:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 编码过虑 -->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring监听 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring MVC DispatcherServlet -->
<servlet>
<servlet-name>springMVC3</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><!--覆盖default servlet的/, springmvc servlet将处理原来处理静态资源的映射 -->
<servlet-name>springMVC3</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--浏览器不支持put,delete等method,由该filter将/blog?_method=delete转换为标准的http delete方法-->
<!-- 解决HTTP PUT请求Spring无法获取请求参数的问题 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>springMVC3</servlet-name>
</filter-mapping>
<display-name>UikitTest</display-name>
<welcome-file-list>
<welcome-file>/WEB-INF/jsp/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
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-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!-- 注解驱动 -->
<mvc:annotation-driven />
<!-- 扫描包 -->
<context:component-scan base-package="com.citic.test.action" />
<!-- 用于页面跳转,根据请求的不同跳转到不同页面,如请求index.do则跳转到/WEB-INF/jsp/index.jsp -->
<bean id="findJsp"
class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="index.do">findJsp</prop><!-- 表示index.do转向index.jsp页面 -->
<prop key="first.do">findJsp</prop><!-- 表示first.do转向first.jsp页面 -->
</props>
</property>
</bean>
<!-- 视图解析 -->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<!-- 返回的视图模型数据需要经过jstl来处理 -->
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 对静态资源文件的访问 不支持访问WEB-INF目录 -->
<mvc:default-servlet-handler />
<!-- 对静态资源文件的访问 支持访问WEB-INF目录 -->
<!-- <mvc:resources location="/uikit-2.3.1/" mapping="/uikit-2.3.1/**" /> -->
<bean id="stringConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- 输出对象转JSON支持 -->
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringConverter"/>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
</beans>
controller
package com.citic.test.action;
import java.util.ArrayList;
import java.util.List;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.citic.test.entity.Person;
/**
* 基于Restful风格架构测试
*
* @author dekota
* @since JDK1.5
* @version V1.0
* @history 2014-2-15 下午3:00:12 dekota 新建
*/
@Controller
public class DekotaAction {
/** 日志实例 */
private static final Logger logger = Logger.getLogger(DekotaAction.class);
@RequestMapping(value = "/hello", produces = "text/plain;charset=UTF-8")
public @ResponseBody
String hello() {
return "你好!hello";
}
@RequestMapping(value = "/say/{msg}", produces = "application/json;charset=UTF-8")
public @ResponseBody
String say(@PathVariable(value = "msg") String msg) {
return "{\"msg\":\"you say:'" + msg + "'\"}";
}
@RequestMapping(value = "/person/{id:\\d+}", method = RequestMethod.GET)
public @ResponseBody
Person getPerson(@PathVariable("id") int id) {
logger.info("获取人员信息id=" + id);
Person person = new Person();
person.setName("张三");
person.setSex("男");
person.setAge(30);
person.setId(id);
return person;
}
@RequestMapping(value = "/person/{id:\\d+}", method = RequestMethod.DELETE)
public @ResponseBody
Object deletePerson(@PathVariable("id") int id) {
logger.info("删除人员信息id=" + id);
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", "删除人员信息成功");
return jsonObject;
}
@RequestMapping(value = "/person", method = RequestMethod.POST)
public @ResponseBody
Object addPerson(Person person) {
logger.info("注册人员信息成功id=" + person.getId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", "注册人员信息成功");
return jsonObject;
}
@RequestMapping(value = "/person", method = RequestMethod.PUT)
public @ResponseBody
Object updatePerson(Person person) {
logger.info("更新人员信息id=" + person.getId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", "更新人员信息成功");
return jsonObject;
}
@RequestMapping(value = "/person", method = RequestMethod.PATCH)
public @ResponseBody
List<Person> listPerson(@RequestParam(value = "name", required = false, defaultValue = "") String name) {
logger.info("查询人员name like " + name);
List<Person> lstPersons = new ArrayList<Person>();
Person person = new Person();
person.setName("张三");
person.setSex("男");
person.setAge(25);
person.setId(101);
lstPersons.add(person);
Person person2 = new Person();
person2.setName("李四");
person2.setSex("女");
person2.setAge(23);
person2.setId(102);
lstPersons.add(person2);
Person person3 = new Person();
person3.setName("王五");
person3.setSex("男");
person3.setAge(27);
person3.setId(103);
lstPersons.add(person3);
return lstPersons;
}
}
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>Uikit Test</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<link rel="stylesheet" type="text/css" href="uikit-2.3.1/css/uikit.gradient.min.css">
<link rel="stylesheet" type="text/css" href="uikit-2.3.1/addons/css/notify.gradient.min.css">
</head>
<body>
<div
style="width:800px;margin-top:10px;margin-left: auto;margin-right: auto;text-align: center;">
<h2>Uikit Test</h2>
</div>
<div style="width:800px;margin-left: auto;margin-right: auto;">
<fieldset class="uk-form">
<legend>Uikit表单渲染测试</legend>
<div class="uk-form-row">
<input type="text" class="uk-width-1-1">
</div>
<div class="uk-form-row">
<input type="text" class="uk-width-1-1 uk-form-success">
</div>
<div class="uk-form-row">
<input type="text" class="uk-width-1-1 uk-form-danger">
</div>
<div class="uk-form-row">
<input type="text" class="uk-width-1-1">
</div>
<div class="uk-form-row">
<select id="form-s-s">
<option>---请选择---</option>
<option>是</option>
<option>否</option>
</select>
</div>
<div class="uk-form-row">
<input type="date" id="form-h-id" />
</div>
</fieldset>
<fieldset class="uk-form">
<legend>基于Restful架构风格的资源请求测试</legend>
<button class="uk-button uk-button-primary uk-button-large" id="btnGet">获取人员GET</button>
<button class="uk-button uk-button-primary uk-button-large" id="btnAdd">添加人员POST</button>
<button class="uk-button uk-button-primary uk-button-large" id="btnUpdate">更新人员PUT</button>
<button class="uk-button uk-button-danger uk-button-large" id="btnDel">删除人员DELETE</button>
<button class="uk-button uk-button-primary uk-button-large" id="btnList">查询列表PATCH</button>
</fieldset>
</div>
<script type="text/javascript" src="js/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="uikit-2.3.1/js/uikit.min.js"></script>
<script type="text/javascript" src="uikit-2.3.1/addons/js/notify.min.js"></script>
<script type="text/javascript">
(function(window,$){
var dekota={
url:'',
init:function(){
dekota.url='<%=basePath%>';
$.UIkit.notify("页面初始化完成", {status:'info',timeout:500});
$("#btnGet").click(dekota.getPerson);
$("#btnAdd").click(dekota.addPerson);
$("#btnDel").click(dekota.delPerson);
$("#btnUpdate").click(dekota.updatePerson);
$("#btnList").click(dekota.listPerson);
},
getPerson:function(){
$.ajax({
url: dekota.url + 'person/101/',
type: 'GET',
dataType: 'json'
}).done(function(data, status, xhr) {
$.UIkit.notify("获取人员信息成功", {status:'success',timeout:1000});
}).fail(function(xhr, status, error) {
$.UIkit.notify("请求失败!", {status:'danger',timeout:2000});
});
},
addPerson:function(){
$.ajax({
url: dekota.url + 'person',
type: 'POST',
dataType: 'json',
data: {id: 1,name:'张三',sex:'男',age:23}
}).done(function(data, status, xhr) {
$.UIkit.notify(data.msg, {status:'success',timeout:1000});
}).fail(function(xhr, status, error) {
$.UIkit.notify("请求失败!", {status:'danger',timeout:2000});
});
},
delPerson:function(){
$.ajax({
url: dekota.url + 'person/109',
type: 'DELETE',
dataType: 'json'
}).done(function(data, status, xhr) {
$.UIkit.notify(data.msg, {status:'success',timeout:1000});
}).fail(function(xhr, status, error) {
$.UIkit.notify("请求失败!", {status:'danger',timeout:2000});
});
},
updatePerson:function(){
$.ajax({
url: dekota.url + 'person',
type: 'POST',//注意在传参数时,加:_method:'PUT' 将对应后台的PUT请求方法
dataType: 'json',
data: {_method:'PUT',id: 221,name:'王五',sex:'男',age:23}
}).done(function(data, status, xhr) {
$.UIkit.notify(data.msg, {status:'success',timeout:1000});
}).fail(function(xhr, status, error) {
$.UIkit.notify("请求失败!", {status:'danger',timeout:2000});
});
},
listPerson:function(){
$.ajax({
url: dekota.url + 'person',
type: 'POST',//注意在传参数时,加:_method:'PATCH' 将对应后台的PATCH请求方法
dataType: 'json',
data: {_method:'PATCH',name: '张三'}
}).done(function(data, status, xhr) {
$.UIkit.notify("查询人员信息成功", {status:'success',timeout:1000});
}).fail(function(xhr, status, error) {
$.UIkit.notify("请求失败!", {status:'danger',timeout:2000});
});
}
};
window.dekota=(window.dekota)?window.dekota:dekota;
$(function(){
dekota.init();
});
})(window,jQuery);
</script>
</body>
</html>
另外,也可以通过springmvc的标签来定义表单,如下:
<form:form action="${ctx}/userinfo${userInfo.userId}" method="put">
</form:form>
生成的html内容如下, 生成一个hidden的_method=put,并于web.xml中的HiddenHttpMethodFilter配合使用,在服务端将post请求改为put请求
<form id="userInfo" action="/springmvc_rest_demo/userinfo/2" method="post">
<input type="hidden" name="_method" value="put"/>
</form>