springmvc细节篇
前面讲了入门篇,现在来了解下springmvc的细节.mvc框架都有请求映射、数据绑定、请求处理、视图解析这几个过程,现在我们来了解springmvc中的这些细节。
1.使用@RequestMapping来配置springmvc请求映射的url
springmvc中的请求映射有多种方式,当然用得最多的是基于注解的请求映射方式.开发中,我们中使用@RequestMapping这个注解来表示controller和方法的url.@RequestMapping的源码:
@Target({ElementType.METHOD, ElementType.TYPE}) // 注解可以用在类和方法上
@Retention(RetentionPolicy.RUNTIME) // 注解在运行期有效
@Documented
@Mapping
public @interface RequestMapping {
String[] value() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
其中value属性用来表示url,其他属性用于限定请求,也就是只有满足某些条件才处理请求.
- value : 指定请求的实际地址,最常用的属性,例如:@RequestMapping(value="/xxx"),value的值可以以"/"开头,也可以不用"/",springmvc会自动补"/".
- method: 指定访问方式,包括POST or GET or others...,默认都支持.以RequestMethod枚举来表示.
例如:@RequestMapping(method=RequestMethod.POST)
- heads: 限定request中必须包含的请求头
例如:限定Content-Type @RequestMapping(headers={"Content-Type=application/x-www-form-urlencoded"})
- consumes: 限定请求头中的Content-Type
例如 : @RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")该方法仅处理ContentType=application/json的请求
- produces: 限定request中Accept
例如:@RequestMapping(value = "/pets/{petId}", method =RequestMethod.GET, produces="application/json")该方法仅处理request中Accept包含application/json的请求
consumes和produces用的比较少,其他几个属性比较常见.
@RequestMapping使用的实例:
@Controller
@RequestMapping(value="/hello")
public class HelloworldController { @RequestMapping(value="/say", //--> 请求url
method={RequestMethod.POST}, // 请求方式为 post
headers={"Content-Type=application/x-www-form-urlencoded"}, // 必须包含ContentType=application/x-www-form-urlencoded,普通表单提交
params={"name=xxx","email=yyy"}) // 请求中必须包含 name=xxx&email=yyy
//params={"name=xxx"})--->请求参数中必须包含
//headers={"Content-Type=application/x-www-form-urlencoded"}) --> 限制请求头
public String sayHello(){
System.out.println("hello");
return "hello";
} }
2.使用@RequestParam和@ModelAttribute完成数据绑定
直白点说,就是如何接收request中的参数呢?springmvc的做法是在方法中定义形式参数,在调用方法时将request中参数赋值给对应的参数,通过注解来描述形参和request中参数的对应关系.
简单例子,调用sayHello方法时,会传一个name参数.程序中如何接收呢?
@RequestMapping(value="/say")
public String sayHello(@RequestParam(value="nm",required=true,defaultValue="zzz")String name){ System.out.println("hello "+name); return "hello";
}
RequestParam有三个属性:
- value: 将request中value对应的参数值绑定到应用注解的变量上,对应上面的例子中:把request中nm的值传给name.
- required:该参数是否必须,true:必须,request不包含此参数则抛异常
- defaultValue:如果request中没有包含value参数,则使用defaultValue值绑定到变量
如果request参数名称和方法中形参名字一样,代码上可以不声明@RequestParam,框架会自动注入.
@RequestParam用来接收单个变量,如果我们要接收的是一个对象呢?例如User(name,email)对象.这时我们可以用另外一个注解@ModelAttribute.该注解的作用就是把request中参数绑定到一个对象上.
@RequestMapping(value="process")
public String process(@ModelAttribute("user")User user){
System.out.println(user);
return "index";
}
接收request的参数搞定了,那如何把数据放到request中,然后带回页面呢?这里有两种一种,一种就是通过ModelAndView对象,一种就是在方法中声明参数.前一种方法在之后视图解析时再说,这里我们将第二种方法.springmvc为解决这个问题提供了一种很优雅的方法,在方法声明Model或者Map的实例,把数据放到Model或者Map中(实际上Model中也是封装了一个Map,只不过Model是以接口的形式提供的),框架在执行方法时会把Model和Map的实例方法request中,这样就可以在页面上通过EL表达式取出页面显示了.这个过程在源码分析那篇中有提到.
@RequestMapping(value="process")
public String process(@ModelAttribute("user")User user,Model model){
System.out.println(user);
// 带参数到页面 jsp上${name}就可以取值
model.addAttribute("name",user.getName());
return "index";
}
@RequestMapping(value="process2")
public String process(@ModelAttribute("user")User user,Map<String,Object> result){
System.out.println(user);
// 带参数到页面 jsp上${name}就可以取值
result.put("name",user.getName());
return "index";
}
3.结果页面的返回
请求处理过程就是调用url对应的方法完成请求的处理的过程,在源码分析篇详细分析了这个过程。这里我们直接讲结果页面的返回.springmvc中提供了一个ModelAndView对象封装结果视图。之前的处理中我们都是返回字符串形式的视图名称,这个字符串最终也会成为ModelAndView对象中的viewName属性,然后交由springmvc中结果视图组件解析.
结果页面返回主要有转发和重定向两种方式,这部分直接看代码:
package cn.springmvc.controller; import java.util.HashMap;
import java.util.Map; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView; @Controller("resultPageController")
@RequestMapping(value="result")
@Scope("prototype")
public class ResultPageController { /****************** 以forward方式返回结果页面 **************************/
@RequestMapping(value="forward1")
public String toViewByForwad1(){
// 逻辑处理 // 转发到index页面-->默认是转发
// return "forward:index";=== return "index";
return "index";
}
@RequestMapping(value="forward2")
public ModelAndView toViewByForwar2(){ // TODO:逻辑处理 ModelAndView mv = new ModelAndView();
mv.setViewName("index");// 默认是转发方式 可以在逻辑视图加forward:也可以不加
// 用ModelAndView可以往request中添加参数
mv.addObject("name","xxx");
return mv;
} /********************** 重定向 的三种方式 ******************************************/
@RequestMapping(value="redirect")
public String redirect(){
// "forword:xxx"
return "redirect:http://www.baidu.com?wd=xx";
} @RequestMapping(value="redirect2")
public ModelAndView redirect2(){
ModelAndView mv = new ModelAndView();
mv.setViewName("redirect:http://www.baidu.com");
mv.addObject("wd","xx");
return mv;
} @RequestMapping(value="redirect3")
public ModelAndView redirect3(){
System.out.println("redirect3");
ModelAndView mv = new ModelAndView();
RedirectView redirectView = new RedirectView("http://www.baidu.com");
Map<String,Object> params = new HashMap<String,Object>();
params.put("wd", "xxxx");
redirectView.setAttributesMap(params);
mv.setView(redirectView);
return mv;
} }
4. CharacterEncodingFilter
web.xml文件中配置编码过滤器.GET方式的乱码问题可以设置tomcat的属性.
<!-- CharacterEncodingFilter 过滤器解决POST方式乱码问题 -->
<filter>
<filter-name>characterEncoding</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>characterEncoding</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
5.springmvc中的文件上传和下载
springmvc文件上传使用的是apache的fileupload组件,所以在springmvc中使用文件上传时先要导入fileupload的jar包.还要在配置文件中配置文件上传的Resolver.
<!-- 文件上传配置 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8" />
<property name="maxUploadSize" value="10485760000" />
<property name="maxInMemorySize" value="40960" />
</bean>
文件上传下载代码示例:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.util.Streams;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.multipart.MultipartFile; @Controller
@RequestMapping(value="file")
public class FileController implements ServletContextAware{ private ServletContext servletContext;
/**
* 1.导入apache fileupload组件
* 2.配置上传文件解析器
*
* 上传单个文件
* @param file
* @return
*/
@RequestMapping("upload")
public String upload(@RequestParam("file") MultipartFile file){
try {
if(file.getSize()>0){ // 判断是否上传了文件
System.out.println(">>>>>>>>> "+file.getOriginalFilename());
String path = servletContext.getRealPath("/up/");
Streams.copy(file.getInputStream(),
new FileOutputStream(path+File.separatorChar+file.getOriginalFilename()),
true);
}
} catch (FileNotFoundException e) {
// TODO 异常处理
e.printStackTrace();
} catch (IOException e) {
// TODO 异常处理
e.printStackTrace();
}
return "index";
}
/**
* 多文件上传
* @param files
* @return
*/
@RequestMapping("uploads")
public String uploads(@RequestParam("files")List<MultipartFile> files){
try {
System.out.println(">>>>>>>>>>>> "+files.size());
String path = servletContext.getRealPath("/up/");
MultipartFile file = null;
for(int i=0;i<files.size();++i){
file = files.get(i);
if(file.getSize()>0) // 判断是否选择了文件
Streams.copy(files.get(i).getInputStream(),
new FileOutputStream(path+File.separatorChar+file.getOriginalFilename()),
true);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "index";
} /**
* 文件下载
*/
@RequestMapping(value="download")
public void download(HttpServletResponse response){
try {
// 下载文件路径
String filePath = this.servletContext.getRealPath("/download/lalalala.png");
File file = new File(filePath); // 设置消息头
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachement;filename="+file.getName());
response.setContentLength((int)file.length()); // 写数据
Streams.copy(new FileInputStream(file),response.getOutputStream(), true); } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
} }
页面代码:
<h4>单文件上传</h4>
<form action="${pageContext.request.contextPath }/file/upload.action" method="post" enctype="multipart/form-data">
<input type="file" name="file"/><br/>
<input type="submit" value="上传">
</form> <h4>多文件上传</h4>
<form action="${pageContext.request.contextPath}/file/uploads.action" method="post" enctype="multipart/form-data">
<input type="file" name="files"/><br/>
<input type="file" name="files"/><br/>
<input type="file" name="files"/><br/>
<input type="submit" value="上传">
</form>
6.springmvc中的json处理
讲springmv与ajax的整合前,先讲两个注解.
@RequestBody:将http请求中的正文(请求体)赋值给应用了注解的参数,通过这个注解可以直接获取请求体的内容.需要注意的是:post请求才有请求体.
@ResponseBody:将数据作为response的正文(响应体)返回.用这个注解可以直接把方法的返回值写到response对象中.通常用于完成ajax请求后服务端数据的返回.
先看两个注解的应用代码:
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import com.alibaba.fastjson.JSON; import cn.jack.domain.User; @Controller("ajaxController")
@RequestMapping(value="ajax")
@Scope("prototype")
public class AjaxController {
/**
* 通过@RequestBody 获取request中的正文
* @param requestBody
* @return
*/
@RequestMapping(value="doReq")
public String process(@RequestBody String requestBody){
System.out.println("----->>>>>>>> "+requestBody);
// do other works
return "index";
} /**
* 通过@ResponseBody 把数据写到response正文中
* @return
*/
@RequestMapping(value="doResp")
@ResponseBody
public String doResp(){
System.out.println(">>>>>>>>>>:reponseBody");
return "retVal";
}
}
页面代码:
<script type="text/javascript" src="${ctx }/js/jquery-1.7.2.js"></script>
<script type="text/javascript">
function doResp(){
var url = '${pageContext.request.contextPath}/ajax/doResp.action';
$.post(url,function(data){
alert(data);
});
} </script> <body>
<h4>@RequestBody: 将消息体绑定到使用了注解的变量,POST请求才有消息体</h4>
<form action="${pageContext.request.contextPath}/ajax/doReq.action" method="post">
<input type="text" name="name" id="name"/><br/>
<input type="text" name="email" id="email"/><br/>
<input type="submit" value="RequestBody" />
</form>
<br/>
<h4>@ResponseBody:将内容写到response响应正文</h4>
<button onclick="doResp();">ResonseBody</button>
</body>
上面说了,@RequestBody和@ResponseBody的作用.接下来使用这两个注解来处理json数据.下面程序的json转换用的是fastjson.
用@ResponseBody返回json字符串.代码如下:
/**
* 用@ResponseBody返回json字符串
*/
@RequestMapping(value="retJson")
@ResponseBody
public String retJson(@RequestParam("userId")Integer userId){
System.out.println("userId>>>>>>>>>>>>>>:"+userId);
User user = new User(); // get User from db by userId
user.setName("zhangsan");
user.setEmail("zhangsan@126.com");
// 返回json字符串
String json = JSON.toJSONString(user);
return json;
} 页面代码:
function _retJson(){
var url = '${pageContext.request.contextPath}/ajax/retJson.action';
var param = {userId:1};
$.post(url,param,function(data){
alert(data);
var user = eval("("+data+")");
alert(user.name+"..."+user.email);
});
}
<button onclick="_retJson();">retJson</button>
@RequestBody接收json字符串,@ResponseBody返回json字符串.
/**
* 用@RequestBody接收json字符串,用@ResponseBody返回json字符串
*/
@RequestMapping(value="doJson")
@ResponseBody
public String doJson(@RequestBody String jsonStr){
System.out.println("requestbody>>>>>>>>:"+jsonStr);
// json字符串 转成对象
User user = JSON.parseObject(jsonStr,User.class);
user.setName("_"+user.getName());
user.setEmail("_"+user.getEmail());
// 对象转成json字符串
String retStr = JSON.toJSONString(user);
return retStr;
}
页面代码:
function _doJson(){
// 获取参数值,拼接json字符串
var name = $("#name").val();
var email = $("#email").val();
// json对象
var json = {name:name,email:email};
// json对象转成json字符串
var jsonStr = JSON.stringify(json);
/**
* 也可以手动拼接json字符串
var jsonStr = "{\"name\":\""+name+"\",\"email\":\""+email+"\"}";
*/
var url = '${pageContext.request.contextPath}/ajax/doJson.action';
//因为发送的json字符串,要设置 Content-Type=application/json
$.ajaxSetup({
contentType:'application/json;charset=UTF-8'
});
// 发送请求
$.post(url,jsonStr,function(data){
alert(data);
// json字符串转json对象
var user = eval("("+data+")");
alert(user.name+"..."+user.email);
});
} <input type="text" name="name" id="name"><br/>
<input type="text" name="email" id="email"><br/>
<button onclick="_doJson();">doJson</button>
@ResponseBody乱码问题的解决,springmvc中StringHttpMessageConverter类默认用的是ISO8859-1编码,所以用@ResponseBody返回中文时会产生乱码问题.解决办法是基于StringHttpMessageConverter写一个Converter,该编码为UTF-8.
import java.nio.charset.Charset; import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter; public class MyStringConvert extends StringHttpMessageConverter{
private static final MediaType mt = new MediaType("text","html",Charset.forName("UTF-8"));// text/html;charset=utf-8
@Override
protected MediaType getDefaultContentType(String t) {
return mt;
}
}
声明AnnotationMethodHandlerAdapter使用自定义的converter.在spring-servlet.xml中配置:
<!-- @ResponseBody返回中文乱码问题 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters" >
<bean class="cn.jack.util.MyStringConvert"></bean>
</property>
</bean>
springmvc细节篇的更多相关文章
- SpringMVC.入门篇《二》form表单
SpringMVC.入门篇<二>form表单 项目工程结构: 在<springmvc入门篇一.HelloWorld>基础上继续添加代码,新增:FormController.ja ...
- SpringMVC.入门篇.一.HelloWorld
SpringMVC.入门篇<一>HelloWorld 项目包结构如下: HelloController.java 代码 package com.charles.controller; im ...
- Java中的泛型 - 细节篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的泛型 - 细节篇>,希望对大家有帮助,谢谢 细心的观众朋友们可能发现了,现在的标题不再是入门篇,而是各种详细篇,细节篇: 是因为之 ...
- 走进spring之springmvc实战篇(二)
本篇继篇一之后加入了jdbc并使用了注解 篇一进行了对spingmvc的基础配置http://www.cnblogs.com/liuyanhao/p/4798989.html 首先让我们先了解下注解的 ...
- 走进spring之springmvc实战篇(一)
本篇运用springmvc来试着写一个登录注册页面 在动手之前,我们需要了解下springnvc.这里先献上一张springmvc的流程图及讲解. Spring的MVC框架是一个基于Dispatche ...
- SpringMVC第二篇【过滤编码器、注解开发、requestMapping、业务方法与传统参数】
SpringMVC过滤编码器 在SpringMVC的控制器中,如果没有对编码进行任何的操作,那么获取到的中文数据是乱码! 即使我们在handle()方法中,使用request对象设置编码也不行!原因也 ...
- springMVC学习篇 - 搭建环境及关键点
springMVC是spring家族中一个重要的组件,和struts一样作为一套前台框架被广泛的应用于各种项目. 之前在很多项目组都用到springMVC,只感觉很强大,但是对这套框架的知识了解比较少 ...
- springmvc基础篇—掌握三种处理器
随着springmvc的广泛使用,关于它的很多实用有效的功能应该更多的被大家所熟知,下面就介绍一下springmvc的三种处理器: 一.BeanName处理器(默认) <?xml version ...
- SpringMVC第一篇【介绍、入门、工作流程、控制器】
什么是SpringMVC? SpringMVC是Spring家族的一员,Spring是将现在开发中流行的组件进行组合而成的一个框架!它用在基于MVC的表现层开发,类似于struts2框架 为什么要使用 ...
随机推荐
- C#中Cookie,Session,Application的用法与区别?
1.Application 储存在服务端,没有时间限制,服务器关闭即销毁(前提是自己没写销毁方法) 2.Session 储存在服务端,客户端(浏览器)关闭即销毁(若长时间不使用 且 浏览器未关闭的情况 ...
- Java - 延迟初始化
延迟初始化(lazy initialization),也就是在真正被使用的时候才开始初始化的技巧. 不论是静态还是实例,都可以进行延迟初始化. 其本质是初始化开销和访问开销之间的权衡. 毕竟是一种优化 ...
- 三角形-->九九乘法表
使用嵌套循环打印九行*组成的三角形: * ** *** ...... *********(9个) public class Triangle { /** * 使用嵌套循环打印九行*组成的三角形 */ ...
- 整理 node-sass 安装失败的原因及解决办法
npm install 时偶尔遇到报错:没有安装python或node-sass 安装失败的问题,百度之后发现是被墙了,但根据百度的方法换了淘宝镜像和用了vpn都安装失败,最后发现原来是因为没有卸载之 ...
- xamarin.Android ImageView 异步加载网络图片
/// <summary> /// 异步获取文件流 /// </summary> /// <param name="url"></para ...
- 新项目找不到Angular-cli.json文件
新项目找不到Angular-cli.json文件 Angular-cli.json文件是Angular5中cli的相关配置信息. 今天创建了新Angular项目后突然发现Angular-cli.jso ...
- 个人遗漏知识的回顾-HTML
常用的一些快捷键: Windows + e 我的电脑Ctrl + Tab 网页间不同页面切换F2 重命名Ctrl+Shift+S 另存为 前端的一些常识:前端意义:将效果图生成网页网页组成:文字.图片 ...
- ubuntu下创建虚拟python3开发环境
友情链接:ubuntu16.04下安装python3+创建虚拟python3开发环境 1.为什么要创建python3虚拟开发环境? /********************************* ...
- Pig安装与应用
1. 参考说明 参考文档: http://pig.apache.org/docs/r0.17.0/start.html#build 2. 安装环境说明 2.1. 环境说明 CentOS7.4+ ...
- demo.testfire.net 靶场测试流程记录
demo.testfire.net span::selection, .CodeMirror-line > span > span::selection { background: #d7 ...