SpringMvc中,requestmethod.get可以同时支持POST GET访问么

spring mvc +spring
aop结合注解的 用户操作日志记录 - 天浩 - ITeye技术网站
博客分类:
参考了网上的一些 文章 但是他们写的不是很全& 自己也是经过了一些摸索& 可以实现 记录 spring mvc controller层操作记录
package com.wssys.
import java.lang.reflect.M
import java.text.SimpleDateF
import java.util.C
import javax.servlet.http.HttpServletR
import org.apache.shiro.SecurityU
import org.aspectj.lang.ProceedingJoinP
import org.aspectj.lang.annotation.A
import org.aspectj.lang.annotation.A
import org.aspectj.lang.annotation.P
import org.springframework.beans.factory.annotation.A
import org.
import org.springframework.web.context.request.RequestContextH
import org.springframework.web.context.request.ServletRequestA
import com.wssys.bean.BolB
import com.PanyF
import com.wssys.bean.DeliverB
import com.wssys.bean.GoodsF
import com.wssys.dao.SyslogD
import com.
import com.wssys.entity.PusFrontU
import com.wssys.entity.PusM
import com.wssys.entity.PusR
import com.wssys.entity.PusSysU
import com.wssys.entity.S
import com.wssys.utils.StringU
import com.wssys.utils.TCPIPU
* @Aspect 实现spring aop 切面(Aspect):
一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。 在Spring
AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @Aspect 注解(@AspectJ风格)来实现。
AOP代理(AOP Proxy): AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。
在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。 注意:Spring
2.0最新引入的基于模式(schema-based
)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来说,代理的创建是透明的。
* @author q
@Component
public class LogService {
@Autowired
private SyslogDao syslogD
public LogService() {
System.out.println("Aop");
* 在Spring
* 2.0中,Pointcut的定义包括两个部分:Pointcut表示式(expression)和Pointcut签名(signature
* )。让我们先看看execution表示式的格式:
* 括号中各个pattern分别表示修饰符匹配(modifier-pattern?)、返回值匹配(ret
* -type-pattern)、类路径匹配(declaring
* -type-pattern?)、方法名匹配(name-pattern)、参数匹配((param
* -pattern))、异常类型匹配(throws-pattern?),其中后面跟着“?”的是可选项。
* @param point
* @throws Throwable
@Pointcut("@annotation(com.wssys.framework.MethodLog)")
public void methodCachePointcut() {
// // @Before("execution(* com.wssys.controller.*(..))")
// public void logAll(JoinPoint point) throws Throwable {
// System.out.println("打印========================");
// // @After("execution(* com.wssys.controller.*(..))")
// public void after() {
// System.out.println("after");
// 方法执行的前后调用
// @Around("execution(* com.wssys.controller.*(..))||execution(* com.bpm.*.web.account.*.*(..))")
// @Around("execution(* com.wssys.controller.*(..))")
// @Around("execution(* org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(..))")
@Around("methodCachePointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
Calendar ca = Calendar.getInstance();
String operDate = df.format(ca.getTime());
String ip = TCPIPUtil.getIpAddr(request);
PusSysUser user = (PusSysUser) SecurityUtils.getSubject()
.getPrincipal();
String loginN
if (user != null) {
loginName = user.getAccount();
// name = user.
loginName = "匿名用户";
// name = "匿名用户";
String monthRemark = getMthodRemark(point);
String monthName = point.getSignature().getName();
String packages = point.getThis().getClass().getName();
if (packages.indexOf("$$EnhancerByCGLIB$$") & -1) { // 如果是CGLIB动态生成的类
packages = packages.substring(0, packages.indexOf("$$"));
} catch (Exception ex) {
ex.printStackTrace();
String operatingcontent = "";
Object[] method_param =
method_param = point.getArgs(); //获取方法参数
// String param=(String) point.proceed(point.getArgs());
object = point.proceed();
} catch (Exception e) {
// 异常处理记录日志..log.error(e);
Syslog sysLog = new Syslog();
sysLog.setIpAddress(ip);
sysLog.setLoginName(loginName);
sysLog.setMethodName(packages + "." + monthName);
sysLog.setMethodRemark(monthRemark);
//这里有点纠结 就是不好判断第一个object元素的类型 只好通过
方法描述来 做一一
转型感觉 这里 有点麻烦 可能是我对 aop不太了解
希望懂的高手在回复评论里给予我指点
//有没有更好的办法来记录操作参数
因为参数会有 实体类 或者javabean这种参数怎么把它里面的数据都解析出来?
if (StringUtil.stringIsNull(monthRemark).equals("会员新增")) {
PusFrontUser pfu = (PusFrontUser) method_param[0];
sysLog.setOperatingcontent("新增会员:" + pfu.getAccount());
} else if (StringUtil.stringIsNull(monthRemark).equals("新增角色")) {
PusRole pr = (PusRole) method_param[0];
sysLog.setOperatingcontent("新增角色:" + pr.getName());
} else if (StringUtil.stringIsNull(monthRemark).equals("用户登录")) {
PusSysUser currUser = (PusSysUser) method_param[0];
sysLog.setOperatingcontent("登录帐号:" + currUser.getAccount());
} else if (StringUtil.stringIsNull(monthRemark).equals("用户退出")) {
sysLog.setOperatingcontent("具体请查看用户登录日志");
} else if (StringUtil.stringIsNull(monthRemark).equals("角色名称修改")) {
PusRole pr = (PusRole) method_param[0];
sysLog.setOperatingcontent("修改角色:" + pr.getName());
} else if (StringUtil.stringIsNull(monthRemark).equals("新增后台用户")) {
PusSysUser psu = (PusSysUser) method_param[0];
sysLog.setOperatingcontent("新增后台用户:" + psu.getAccount());
} else if (StringUtil.stringIsNull(monthRemark).equals("更新菜单")) {
PusMenu pm = (PusMenu) method_param[0];
sysLog.setOperatingcontent("更新菜单:" + pm.getName());
} else if (StringUtil.stringIsNull(monthRemark).equals("保存菜单")) {
PusMenu pm = (PusMenu) method_param[0];
sysLog.setOperatingcontent("保存菜单:" + pm.getName());
} else if (StringUtil.stringIsNull(monthRemark).equals("修改公司")) {
ComPanyForm ciform = (ComPanyForm) method_param[0];
sysLog.setOperatingcontent("修改公司:" + ciform.getName());
} else if (StringUtil.stringIsNull(monthRemark).equals("联系人更新")) {
Companycontacts ct = (Companycontacts) method_param[0];
sysLog.setOperatingcontent("联系人更新:" + ct.getName());
} else if (StringUtil.stringIsNull(monthRemark).equals("修改货物")) {
GoodsForm goodsForm = (GoodsForm) method_param[0];
sysLog.setOperatingcontent("修改货物(货物id/编号):" + goodsForm.getId());
} else if (StringUtil.stringIsNull(monthRemark).equals("打印出库单")) {
DeliverBean owh= (DeliverBean) method_param[0];
sysLog.setOperatingcontent("出库单单号:" + owh.getCknum());
} else if (StringUtil.stringIsNull(monthRemark).equals("打印提单")) {
BolBean bol= (BolBean) method_param[0];
sysLog.setOperatingcontent("提货单号:" + bol.getBolnum());
} else if (StringUtil.stringIsNull(monthRemark).equals("系统左侧菜单查询")) {
sysLog.setOperatingcontent("无");
sysLog.setOperatingcontent("操作参数:" + method_param[0]);
syslogDao.save(sysLog);
// 方法运行出现异常时调用
// @AfterThrowing(pointcut = "execution(* com.wssys.controller.*(..))",
// throwing = "ex")
public void afterThrowing(Exception ex) {
System.out.println("afterThrowing");
System.out.println(ex);
// 获取方法的中文备注____用于记录用户的操作日志描述
public static String getMthodRemark(ProceedingJoinPoint joinPoint)
throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
String methode = "";
for (Method m : method) {
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length) {
MethodLog methodCache = m.getAnnotation(MethodLog.class);
if (methodCache != null) {
methode = methodCache.remark();
spring application.xml配置:
& &!-- aop --&
& &bean id="logService" class="com.wssys.framework.LogService"&&/bean&
&& &!-- 启动对@AspectJ注解的支持& --&
&& &aop:aspectj-autoproxy proxy-target-class="true" /&
spring mvc controller层action的
设置 例如:
@RequestMapping(value = "/addFrontUser", method = RequestMethod.POST)
@MethodLog(remark = "会员新增")
public String saveFrontUserAction(@ModelAttribute("psu") PusFrontUser pfu,
BindingResult result, SessionStatus status,
HttpServletResponse response) {
if (pusFrontUserDao.checkAccount(pfu.getAccount()) & 0) {
PrintWriter out =
out = response.getWriter();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
out.write("保存失败,会员帐号已经存在");
out.flush();
// Timestamp now = new Timestamp(System.currentTimeMillis());// 获取系统当前时间
int saverec = 0;
pfu.setPwd(new Sha384Hash(pfu.getPwd()).toBase64());
saverec = pusFrontUserDao.save(pfu);
PrintWriter out =
out = response.getWriter();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
if (saverec & 0) {
out.write("保存成功,您可以继续保存或者关闭当前页面");
out.write("保存失败");
out.flush();
package com.wssys.
import java.lang.annotation.D
import java.lang.annotation.ElementT
import java.lang.annotation.R
import java.lang.annotation.RetentionP
import java.lang.annotation.T
* 表示对标记有xxx注解的类,做代理 注解@Retention可以用来修饰注解,是注解的注解,称为元注解。
* Retention注解有一个属性value,是RetentionPolicy类型的,Enum RetentionPolicy是一个枚举类型,
* 这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配
* RententionPolicy使用。RetentionPolicy有3个值:CLASS RUNTIME SOURCE
* 用@Retention(RetentionPolicy
* .CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候;
* 用@Retention(RetentionPolicy.SOURCE
* )修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中;
* 用@Retention(RetentionPolicy.RUNTIME
* )修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时,
* 所以他们可以用反射的方式读取。RetentionPolicy.RUNTIME
* 可以让你从JVM中读取Annotation注解的信息,以便在分析程序的时候使用.
* 类和方法的annotation缺省情况下是不出现在javadoc中的,为了加入这个性质我们用@Documented
@interface Annotation{ } 定义一个注解 @Annotation,一个注解是一个类。
@interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字
* @author q
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
String remark() default "";
String operType() default "0";
// String desc() default "";
日志 数据效果:
基本可以实现监控用户的数据操作
aop 太吊了
改变了传统 的 每个日志必须去一个个的方法里写的 方式
直接通过 反射 得到所有数据 一个 类解决
开发不是一般的快
这个过程中为了 做这个功能对spring aop 只是匆匆的看了一遍& 接下来的时间有空就得好好研究下该技术 的原理以及实现
lz能不能给份代码学习下
/blog/2147058 已经分享
q 写道你好 请教你一下& 你有没有遇到方法被拦截了两次这种情况?& 方便的话 邮件联系:那倒没有环回吧。
楼主,您好,我看了您的帖子之后,自己动手尝试写了下。发现在springmvc中无法使用,能否将配置贴出来呢?纠结了5个小时了。。。如果方便的话,QQ交流吧。。。
。&&&&&&& 【自己最开始用的struts,没有考虑到mvc框架会和spring都扫描包,springmvc和spring配置加载顺序问题】发现怎么配置都不能正常的切入到项目。最开始以为是spring没有正确生成切面对象,后来发现是servlet-mvc.xml扫描了我要切入的对象,那么spring去扫描的时候发现内存中已经有了该对象就不再对其进行aop增强或者事务控制,于是,在spring-mvc配置文件中去掉了扫描service的路径,一切恢复正常,因为service层是我要切入的面。所以应该是由spring来管理。spring-mvc.xml部分配置[code=html]&!-- 扫描的时候过滤掉Service层,aop要在service进行切入!& --& &context:component-scan base-package="audit"&
&context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/& &/context:component-scan& &context:component-scan base-package="com.buyantech.log"&
&context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/&
&/context:component-scan&spring部分配置[code=html]&context:component-scan base-package="com.**.service" /&
你好 请教你一下& 你有没有遇到方法被拦截了两次这种情况?& 方便的话 邮件联系:那倒没有
浏览: 152728 次
来自: 宁波
aib628 写道你好请问一下,我问的刚好是shiro1.2. ...
你好请问一下,我问的刚好是shiro1.2.2
有这个一个问 ...
要是maven的 就不用fork了。
tiger_a 写道下了半天没得反应啊,亲,我书读的少,你不要 ...大家好,请教个问题, 我接收一个客户端用post发送的数据,但是这个数据只有内容,发送的时候没有指定name,所以在后台request中是用getParameter(..)这类方法是取不到的。 但是调试的时候, 在request中有个postData数组,这个里面的值该怎么取? 我用的是spring mvc, 这个和spring mvc其实也没什么关系,我没找到jsp版,就发到spring板块儿了。
问题补充:前台发送数据时的http报文:
POST /mobile HTTP/1.0
Host: 183.16.34.254:12345
Server-id:xxxxxxxxx
IMEI-id:xxxxxxxxxxxxxxx
IMSI-id:xxxxxxxxxxxxxxx
Content-Length: xx
[,59,Q9-B-II-01@027@@]
这种post请求,无参数的话,可以使用流的方式,获取到post过来的数据
&&&&&&& InputStream is =
&&&&&&& try {
&&&&&&&&&&& is = request.getInputStream();
&&&&&&&&&&& BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
&&&&&&&&&&& //读取HTTP请求内容
&&&&&&&&&&& String buffer =
&&&&&&&&&&& StringBuffer sb = new StringBuffer();
&&&&&&&&&&& while ((buffer = br.readLine()) != null) {
&&&&&&&&&&&&&&& sb.append(buffer);
&&&&&&&&&&& }
&&&&&&&&&&& String notifyMessage = sb.toString();
&&&&&&&& } catch (IOException e) {
&&&&&&&&&&& logger.error("error& info");
&&&&&&&&& }
没有指定NAME,会不会“内容”本身被作为KEY,至于参数中,看下ParameterKey,是的话 从直接取KEY。
1.String[] postData = request.getParameterValues("postData ");//
.....N行,N=对象中的属性的个数
然后写个for循环,按照其中一个数组来循环,
for (int i = 0; i & postData . i++) {
&&& 先new对象,然后根据属性一次赋值,这些数组中的属性和前台的顺序是一致的
}
2.
class postDataArray {
&&& private postData postDatas[] ;
&&& public void setPostDatas(postData[] postDatas) {
this.postDatas= postD
&&& }
&&& public postData[] postDatas() {
return postD
&&& }
}
//用 postData作参数
@RequestMapping(value ="xxx" , method = RequestMethod.POST)
public ModelAndView doget(postDataArray param){& }
/* 页面用下面的方式 */
&input name="postDatas[0].name" value="name1" /&
&input name="postDatas[0].address" value="address1" /&
&input name="postDatas[1].name" value="name2" /&
&input name="postDatas[1].address" value="address2" /&
&input name="postDatas[2].name" value="name3" /&
&input name="postDatas[2].address" value="address3" /&
已解决问题
未解决问题基于Spring MVC的Web应用开发(6) - Response - Stay Hungry, Stay Foolish - ITeye技术网站
博客分类:
本文讲解Spring MVC的Response,深入了解一下@RequestMapping配合@ResponseBody的用法,同时介绍另外一个和Response有关的类ResponseEntity。
首先看看本文演示用到的类ResponseController:
package org.springframework.samples.mvc.
import org.springframework.http.HttpH
import org.springframework.http.HttpS
import org.springframework.http.MediaT
import org.springframework.http.ResponseE
import org.springframework.stereotype.C
import org.springframework.web.bind.annotation.RequestM
import org.springframework.web.bind.annotation.RequestM
import org.springframework.web.bind.annotation.ResponseB
@Controller
public class ResponseController {
@RequestMapping(value="/response/annotation", method=RequestMethod.GET)
public @ResponseBody String responseBody() {
return "The String ResponseBody";
@RequestMapping(value="/response/charset/accept", method=RequestMethod.GET)
public @ResponseBody String responseAcceptHeaderCharset() {
return "こんにちは世界! (\"Hello world!\" in Japanese)";
@RequestMapping(value="/response/charset/produce", method=RequestMethod.GET, produces="text/charset=UTF-8")
public @ResponseBody String responseProducesConditionCharset() {
return "こんにちは世界! (\"Hello world!\" in Japanese)";
@RequestMapping(value="/response/entity/status", method=RequestMethod.GET)
public ResponseEntity&String& responseEntityStatusCode() {
return new ResponseEntity&String&("The String ResponseBody with custom status code (403 Forbidden - stephansun)",
HttpStatus.FORBIDDEN);
@RequestMapping(value="/response/entity/headers", method=RequestMethod.GET)
public ResponseEntity&String& responseEntityCustomHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return new ResponseEntity&String&("The String ResponseBody with custom header Content-Type=text/plain",
headers, HttpStatus.OK);
访问,对应responseBody(),这个方法很典型,之前已经见过多次了,将字符串直接输出到浏览器。
访问,对应responseAcceptHeaderCharset(),该方法和responseBody()并没有什么不同,只是,返回的字符串中带有日文。浏览器显示"???????? ("Hello world!" in Japanese)",有乱码出现。
访问,对应responseProducesConditionCharset(),该方法跟responseAcceptHeaderCharset()相比,在@RequestMapping中增加了“produces="text/charset=UTF-8"”,浏览器显示"こんにちは世界! ("Hello world!" in Japanese)",乱码没有了。
为了将这两者的区别说清楚,看看日志:
responseAcceptHeaderCharset():
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [こんにちは世界! ("Hello world!" in Japanese)] as "text/html" using [org.springframework.http.converter.StringHttpMessageConverter@6b414655]
responseProducesConditionCharset():
DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Written [こんにちは世界! ("Hello world!" in Japanese)] as "text/charset=UTF-8" using [org.springframework.http.converter.StringHttpMessageConverter@6b414655]
前者使用默认的"text/html",后者使用了特定的"text/charset=UTF-8"。为什么以"text/html"形式输出日文(其实中文也是一样的)就会乱码的根本原因我还没透彻地搞清楚,但我注意到spring-web-3.1.0.REALEASE.jar中org.springframework.http.converter.StringHttpMessageConverter中有这样一段代码:
public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
应该跟"ISO-8859-1"有关系吧。
后者通过指定@RequestMapping的produces属性为text/plain,字符集为UTF-8,可以避免乱码,这个是可以理解的。
最后看看responseEntityStatusCode()和responseEntityCustomHeaders()方法,这两个方法和前面的方法的区别是没有@ResponseBody,返回的类型为ResponseEntity&String&。
responseEntityStatusCode()方法返回一个字符串,并附带了HTTP状态码为HttpStatus.FORBIDDEN(即403);
responseEntityCustomHeaders()除了返回一个字符串,HTTP状态码为HttpStatus.OK(即200),还指定了返回内容的content-type为text/plain;
这里最容易困惑我们的就是HTTP状态码了,因为从浏览器的输出看不到任何与HTTP状态码相关的东西。
均能正常的将字符串内容显示在网页上,那么HttpStatus.FORBIDDEN起什么作用呢?
ResponseEntity继承于HttpEntity类,HttpEntity类的源代码的注释说"HttpEntity主要是和RestTemplate组合起来使用,同样也可以在SpringMVC中作为@Controller方法的返回值使用"。ResponseEntity类的源代码注释说"ResponseEntity是HttpEntity的扩展,增加了一个HttpStutus的状态码,通常和RestEntity配合使用,当然也可以在SpringMVC中作为@Controller方法的返回值使用"。那么使用RestTemplate写个程序模拟一下吧(RestTemplate的具体用法见本文附录):
package org.springframework.samples.mvc.
import org.springframework.http.HttpS
import org.springframework.http.MediaT
import org.springframework.http.ResponseE
import org.springframework.web.client.RestT
public class ResponseControllerTest {
public static void main(String[] args) {
RestTemplate template = new RestTemplate();
ResponseEntity&String& entity = template.getForEntity(
"http://localhost:8080/web/response/entity/status", String.class);
String body = entity.getBody();
MediaType contentType = entity.getHeaders().getContentType();
HttpStatus statusCode = entity.getStatusCode();
System.out.println("statusCode:[" + statusCode + "]");
访问,观察日志:
DEBUG: org.springframework.web.client.RestTemplate - Created GET request for "http://localhost:8080/web/response/entity/status"
DEBUG: org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, */*]
WARN : org.springframework.web.client.RestTemplate - GET request for "http://localhost:8080/web/response/entity/status" resulted in 403 (Forbidden); invoking error handler
Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 403 Forbidden
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:76)
at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:486)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:443)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:221)
at org.springframework.samples.mvc.response.ResponseControllerTest.main(ResponseControllerTest.java:12)
将URL换成,观察日志:
DEBUG: org.springframework.web.client.RestTemplate - Created GET request for "http://localhost:8080/web/response/entity/headers"
DEBUG: org.springframework.web.client.RestTemplate - Setting request Accept header to [text/plain, */*]
DEBUG: org.springframework.web.client.RestTemplate - GET request for "http://localhost:8080/web/response/entity/headers" resulted in 200 (OK)
DEBUG: org.springframework.web.client.RestTemplate - Reading [java.lang.String] as "text/plain" using [org.springframework.http.converter.StringHttpMessageConverter@2e297ffb]
statusCode:[200]
发现使用RestTemplate时,如果它发现返回的信息中HTTP状态码为403时,就抛出异常了,正好符合了我们的期望,至于为什么浏览器上没有体现,暂时还不不太明白(待补完)。
===================================================================
是关于@RequestMapping的produces属性的讨论。
===================================================================
附录中的相关内容:
[了解一下@RequesetMapping支持的返回值类型]
16.3.3.2 @RequestMapping注解方法支持的返回值类型
以下返回值的类型(return types)均支持:
ModelAndView对象,with the model implicitly enriched with command objects and the results of @ModelAttributes annotated reference data accessor methods.(恕我实在翻译不出 TAT)。
Model对象,with the view name implicitly determined through a RequestToViewNameTranslator and the model implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
Map对象,for exposing a model, with the view name implicitly determined through a RequestToViewNameTranslator and the model implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
View对象,with the model implicitly determined through command objects and @ModelAttribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a Model argument (see above).
String,value that is interpreted as the logical view name, with the model implicitly determined through command objects and @ModelAttribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a Model argument (see above).
void,if the method handles the response itself (by writing the response content directly, declaring an argument of type ServletResponse / HttpServletResponse for that purpose) or if the view name is supposed to be implicitly determined through a RequestToViewNameTranslator (not declaring a response argument in the handler method signature).
@ResponseBody,If the method is annotated with @ResponseBody, the return type is written to the response HTTP body. The return value will be converted to the declared method argument type using HttpMessageConverters. See Section 16.3.3.5, “Mapping the response body with the @ResponseBody annotation”.
HttpEntity或者ResponseEntity,HttpEntity&?&或者ResponseEntity&?&对象可以取到Servlet的response的HTTP头信息(headers)和内容(contents)。这个实体(entity body)可以通过使用HttpMessageConverter类被转成Response流。See Section 16.3.3.6, “Using HttpEntity&?&”.
Any other return type is considered to be a single model attribute to be exposed to the view, using the attribute name specified through @ModelAttribute at the method level (or the default attribute name based on the return type class name). The model is implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
[了解一下RestTemplate,下一篇文章有用]文档中有关RestTemplate的内容:
20.9 在客户端访问RESTful服务
RestTemplate是客户端访问RESTful服务的核心类。它在概念上同Spring中的其它模板类相似,如JdbcTemplate和JmsTemplate还有一些其它Spring portfolio工程中的模板类。RestTemplate提供了一个回调方法,使用HttpMessageConverter将对象marshal到HTTP请求体里,并且将response unmarshal成一个对象。使用XML作为消息格式是一个很普遍的做法,Spring提供了MarshallingHttpMessageConverter类,该类使用了Object-to-XML框架,该框架是org.springframe.oxm包的一部分。你有多种XML到Object映射技术可选。
本节介绍了如何使用RestTemplate以及和它相关的HttpMessageConverters。
20.9.1 RestTemplate
在Java中调用RESTful服务的一个经典的做法就是使用一个帮助类,如Jakarta Commons的HttpClient,对于通用的REST操作,HttpClient的实现代码比较底层,如下:
String uri = "/hotels/1/bookings";
PostMethod post = new PostMethod(uri);
String request = // create booking request content
post.setRequestEntity(new StringRequestEntity(request));
httpClient.executeMethod(post);
if (HttpStatus.SC_CREATED == post.getStatusCode()) {
Header location = post.getRequestHeader("Location");
if (location != null) {
System.out.println("Created new booking at :" + location.getValue());
RestTemplate对HTTP的主要六种提交方式提供了更高层的抽象,使得调用RESTful服务时代码量更少,并且使REST表现的更好。
表格20.1 RestTemplate方法预览
HTTP方法 RestTemplate方法
DELETE delete
GET getForObject getForEntity
HEAD headForHeaders(String url, String... urlVariables)
OPTIONS optionsForAllow(String url, String... urlVariables)
POST postForLocation(String url, Object request, String... urlVariables) postForObject(String url, Object request, Class&T& responsetype, String... uriVariables)
PUT put(String url, Object request, String... urlVariables)
RestTemplate的方法名称遵循着一个命名规则,第一部分说明调用的是什么HTTP方法,第二部分说明的是返回了什么。比如,getForObject()方法对应GET请求,将HTTP response的内容转成你需要的一种对象类型,并返回这个对象。postForLocation()方法对应POST请求,converting the given object into a HTTP request and return the response HTTP Location header where the newly created object can be found.如果在执行一个HTTP请求时出现异常,会抛出RestClientException异常;可以在RestTemplate自定义ResponseErrorHandler的实现来自定义这种异常。
这些方法通过HttpMessageConverter实例将传递的对象转成HTTP消息,并将得到的HTTP消息转成对象返回。给主要mime类型服务的转换器(converter)默认就注册了,但是你也可以编写自己的转换器并通过messageConverters()bean属性注册。该模板默认注册的转换器实例是ByteArrayHttpMessageConverter,StringHttpMessageConverter,FormHttpMessageConverter以及SourceHttpMessageConverter。你可以使用messageConverters()bean属性重写这些默认实现,比如在使用MarshallingHttpMessageConverter或者MappingJacksonHttpMessageConverter时你就需要这么做。
每个方法有有两种类型的参数形式,一种是可变长度的String变量,另一种是Map&String, String&,比如:
String result = restTemplate.getForObject("/hotels/{hotel}/bookings/{booking}",
String.class,"42", "21");
使用可变长度参数,
Map&String, String& vars = Collections.singletonMap("hotel", "42");
String result =
restTemplate.getForObject("/hotels/{hotel}/rooms/{hotel}", String.class, vars);
使用一个Map&String, String& 。
你可以直接使用RestTemplate的默认构造器创建一个RestTemplate的实例。它会使用jdk中java.net包的标准Java类创建HTTP请求。你也可以自己指定一个ClientHttpRequestFactory的实现。Spring提供了CommonsClientHttpRequestFactory的实现,该类使用了Jakarta Commons的HttpClient创建HTTP请求。CommonsClientHttpRequestFactory配置了mons.httpclient.HttpClient的一个实例,该实例反过来被credentials information或者连接池配置。
前面那个使用了Jakarta Commons的HttpClient类的例子可以直接使用RestTemplate重写,如下:
uri = "/hotels/{id}/bookings";
RestTemplate template = new RestTemplate();
Booking booking = // create booking object
URI location = template.postForLocation(uri, booking, "1");
通用的回调接口是RequestCallback,该接口在execute方法被调用时被调用。
public &T& T execute(String url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor&T& responseExtractor,
String... urlVariables)
// also has an overload with urlVariables as a Map&String, String&.
RequestCallback接口定义如下:
public interface RequestCallback {
void doWithRequest(ClientHttpRequest request) throws IOE
该接口允许你管控(manipulate)request的header并且象request体中写数据。当使用execute方法时,你不必担心任何资源管理问题的,模板总是会关闭request,并且处理任何error,你可以参考API文档来获得更多有关使用execute方法及该模板其它方法参数含义的信息。
20.9.1.1 同URI一起工作
对HTTP的主要方法,RestTemplate的第一个参数是可变的,你可以使用一个String类型的URI,也可以使用java.net.URI类型的类,
String类型的URI接受可变长度的String参数或者Map&String, String&,这个URL字符串也是假定没有被编码(encoded)并且需要被编码的(encoded)的。举例如下:
restTemplate.getForObject("/hotel list", String.class);
这行代码使用GET方式请求。这意味着如果输入的URL字符串已经被编码了(encoded),它将被编码(encoded)两次 -- 比如:会变成。如果这不是你所希望的,那就使用java.net.URI,它假定URL已经被编码(encoded)过了,如果你想要将一个单例的URI(fully expanded)复用多次的话,这个方法也是有用的。
UriComponentsBuilder类(我们已经见过了,不是吗? 译者)可以构建和编码一个包含了URI模板支持的URI,比如你可以从一个URL字符串开始:
UriComponents uriComponents =
UriComponentsBuilder.fromUriString("/hotels/{hotel}/bookings/{booking}").build()
.expand("42", "21")
.encode();
URI uri = uriComponents.toUri();
或者单独地指定每个URI组件:
UriComponents uriComponents =
UriComponentsBuilder.newInstance()
.scheme("http").host("").path("/hotels/{hotel}/bookings/{booking}").build()
.expand("42", "21")
.encode();
URI uri = uriComponents.toUri();
20.9.1.2 处理request和response的头信息(headers)
除了前面已经说到的方法外,RestTemplate还有一个exchange()方法,该方法可以用在基于HttpEntity类的任意HTTP方法的执行上。
也许最重要的一点是,exchange()方法可以用来添加request头信息(headers)以及读response的头信息(headers)。举例:
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("MyRequestHeader", "MyValue");
HttpEntity&?& requestEntity = new HttpEntity(requestHeaders);
HttpEntity&String& response = template.exchange("/hotels/{hotel}",
HttpMethod.GET, requestEntity, String.class, "42");
String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();
在上面这个例子中,我们首先准备了一个request实体(entity),该实体包含了MyRequestHeader头信息(header)。然后我们取回(retrieve)response,读到这个MyResponseHeader和返回体(body)。
20.9.2 HTTP Message Conversion (本小节跟本文关系不大,略去 译者)
===================================================================
浏览 13917
stephansun
浏览: 102053 次
来自: 上海
谢谢啊~学习了~~
你好,能分享下demo吗?不慎感激。
is good Thanks.
Mark 下,最近正在研究安全相关的东西}

我要回帖

更多关于 springmvc post提交 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信