1)@SessionAttributes绑定命令对象到session
@SessionAttributes(String[] value,Class[] type)
@SessionAttributes(value={},types={})
@SessionAttributes(value={"user"})写在处理器类上面
表示将模型数据中的名字为"user" 的对象存储到会话中,此处value指定将模型数据中的哪些数据(名字进行匹配)存储到会话中,此外还有一个types属性表示模型数据中的哪些类型的对象存储到会话范围内,如果同时指定value和types属性则那些名字和类型都匹配的对象才能存储到会话范围内。
注意,模型数据的作用范围是request级别的,所以一次请求过后,之前模型中的数据就没有了,@SessionAttributes注解可以将当前模型中指定的数据存放到session中,并且还可以从session中把指定数据取出来返回模型中。
1.如果模型里有名字为user的数据,并且使用了@SessionAttributes("user"),那么这个模型中的数据user会被放到session中
2.如果要从模型中拿名字为user的数据,模型中没有,这个时候就拿不到了,但是这个时候使用了@SessionAttributes("user"),那么它会帮我们把数据从session取出来放到模型中
所以处理器类的上面有没有加@SessionAttributes("user")注解,会影响到我们使用下面方式是否能拿到值
@RequestMapping("/session")
public String session(User u) {
System.out.println(u);
return "index";
}
默认只是从模型中拿名字叫user的值,如果加了@SessionAttributes("user")这个注解,还可以拿到session中的user对象
也可以指定用哪个名字拿值,例如:
@RequestMapping("/session")
public String session(@ModelAttribute("my_user") User u) {
System.out.println(u);
return "index";
}
也可以使用SessionStatus对象的方法把@SessionAttributes指定的数据从session中清除掉
@RequestMapping("/session")
public String session(User u,SessionStatus status) {
if(true){
//从session中清除注解中指定的数据
status.setComplete();
}
System.out.println(u);
return "index";
}
2)@Value绑定SpEL表示式
用于将一个SpEL表达式结果映射到到功能处理方法的参数上。
public String test(@Value("#{systemProperties['java.vm.version']}") String jvmVersion){
System.out.println(jvmVersion);
return "index";
}
SpEL表达式的使用,例如:
取名字为stu的bean的name字段的值,这里指的是property
public String test(@Value("#{stu.name}") String username)
对其他bean中某个方法的引用
public String test(@Value("#{stu.sayHello()}") String username)
public String test(@Value("#{stu.sayHello('tom')}") String username)
表达式(?.)可以确保在sayHello()返回不为空的情况下调用toUpperCase()方法,如果返回空那么不继续调用后面的方法
public String test(@Value("#{stu.sayHello()?.toUpperCase()}") String username)
如果要调用的某个类是外部类,而不是spring中定义的bean,使用表达式T()
public String test(@Value("#{T(java.lang.Math).random()}") String username)
3)@InitBinder注解
可以解决类型转换的问题
例如一个表单提交数据给Controller,表单中有日期数据
@Controller
public class InitBinderController{
@RequestMapping(value="/register",method=RequestMethod.GET)
public String registerPage(){
return "register";
}
@RequestMapping(value="/register",method=RequestMethod.POST)
public String register(User user){
System.out.println("user = "+user);
return "index";
}
}
表单提交的时候有一个字符串形式的日期数据"1999-10-23",SpringMVC默认不支持这个格式的转换,所以需要手动配置日期类型的转换,否则会报错。
在这个Controller中加入写一个转换的方法,加上@InitBinder即可
@Controller
public class InitBinderController{
@InitBinder
public void test(WebDataBinder binder){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
//true表示允许为空
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
@RequestMapping(value="/register",method=RequestMethod.GET)
public String registerPage(){
return "register";
}
@RequestMapping(value="/register",method=RequestMethod.POST)
public String register(User user){
System.out.println("user = "+user);
return "index";
}
}
在Spring3中引入了一个Converter接口,它支持从一个任意类型转为另一个任意类型。
例如:
自己编写的转换器代码:
public class StringToDateConverter implements Converter<String, Date>{
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date convert(String str) {
Date date = null;
try {
if(str!=null&&!"".equals(str.trim())){
date = dateFormat.parse(str);
}
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
}
spring的配置文件:例如spring的一个工厂类,产生一个转换服务,同时把我们自己的转换器注入进去,可以有多个
<bean name="formatService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.briup.web.converter.StringToDateConverter"></bean>
</set>
</property>
</bean>
//在mvc标签中指定这个转换服务器
<mvc:annotation-driven conversion-service="formatService"/>
还有另外一种解决日期的方式,就是利用spring提供的一个专门针对日期转换的注解:@DateTimeFormat(pattern="yyyy-MM-dd")
例如:
public class User {
private String username;
private String password;
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date dob;
get/set
}
注意这个时候就不需要我们再写自定义的转换器了,但是如果是其他类型的转换,我们还得需要自己编写自定义的类型转换器
4)@RequestBody注解
可以接收客户端ajax请求中的json数据并且转换为对象,但是只能接收post请求中的数据,因为post请求的数据在请求体中(request-body).
需要引入俩个json相关jar包:
jackson-mapper-asl-1.9.13.jar
jackson-core-asl-1.9.13.jar
注意:在javascript中,json对象和字符串之间的转换:
JSON.stringify(obj)将JSON转为字符串。
JSON.parse(string) 将字符串转为JSON格式;
例如:
处理器中代码:
@RequestMapping(value="/json/update",consumes="application/json",method=RequestMethod.POST)
public void update(@RequestBody User user,Writer out)throws Exception{
System.out.println("user = "+user);
out.write("helloworld");
}
页面js中代码:
注意:http中的Content-Type,在jquery中是contentType
$("#btn").on("click",function(){
var json = {username:"tom",password:"123",dob:"1999-10-27"};
$.ajax({
type:"post",
url:"json/update",
contentType:"application/json",
data:JSON.stringify(json),
dataType:"text",
success:function(data){
console.log("data = "+data);
}
});
});
客户端使用ajax发送json数据给Controller,Controller里面接收json数据并且转换为对象
1.ajax请求发送的时候要指定为post方式
2.ajax请求发送的时候要指定contentType:"application/json"
3.ajax请求发送的时候要把json对象转换为字符串再发送
4.Controller中要使用@RequestBody指定接收数据的参数
5.项目中要引入俩个json相关的jar包
6.如果此ajax请求还希望Controller返回的数据也是json格式的,那么需要在发送ajax请求的时候指定dataType:"json",
7.Controller中的方法要返回json格式的数据给客户端,可以使用@ResponseBody标签 或者 在方法中自己使用response对象获得io流给客户端写回去
注意:
ajax发送请求的时候,请求头中的Content-Type默认值是: application/x-www-form-urlencoded,表示当前请求中如果有数据的话,将会是key=value&key=value的形式
5)@ResponseBody注解
该注解用于将处理器中功能处理方法返回的对象,经过转换为指定格式后,写入到Response对象的body数据区(响应正文).一般返回的数据不是html标签的页面,而是其他某种格式的数据时使用,例如给ajax请求返回json数据.
例如:在@RequestBody的例子中进行修改
处理器中代码:添加了@ResponseBody,修改了方法的返回值
@RequestMapping(value="/json/respbody",consumes="application/json",method=RequestMethod.POST)
@ResponseBody
public User update(@RequestBody User user)throws Exception{
System.out.println("user = "+user);
user.setUsername("张三");
user.setPassword("123");
user.setDob(new Date());
return user;
}
页面js中代码: 注意这里的dataType属性的值
$("#btn").on("click",function(){
var json = {username:"tom",password:"123",dob:"1999-10-27"};
$.ajax({
type:"post",
url:"json/respbody",
contentType:"application/json",
data:JSON.stringify(json),
dataType:"json",
success:function(data){
console.log("data = "+data);
console.log(data.username);
console.log(data.password);
console.log(data.dob);
}
});
});
这里还是会有日期的问题,就是把user对象放入响应正文返回给客户端后,被转换为了json对象,从firebug中可以看出,这个返回的json对象为{"username":"张三","password":"123","dob":1478621620119},它默认把dob这个日期对象转为了一个时间戳
如果我们想按照自己的日期格式进行转换,那么需要这样处理:
自定义一个json的日期类型格式化类:
public class DateJsonSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String formattedDate = formatter.format(value);
jgen.writeString(formattedDate);
}
}
在User类中的getDob方法上添加注解
@JsonSerialize(using=DateJsonSerializer.class)
public Date getDob() {
return dob;
}
@ResponseBody注解可以处理以下常见类型的返回值,如果可以的话还会把返回值转换为json格式字符串
1.单值(基本数据类型和字符串)
2.bean对象(例如User对象、Student对象等,对象中需要有property)
3.数组
4.List/Set集合
5.Map集合
6).@Scope注解
Controller默认情况下和servlet一样也是单例,但是spring提供了一个@Scope注解可以让Controller对象变为非单例,只需在Controller类上面加入@Scope("prototype")即可
可以利用容器的scope="prototype"来保证每一个请求有一个单独的Action来处理, 避免struts中Action的线程安全问题。
例如:
@Controller
@RequestMapping("/hello")
@Scope("prototype")
public class HelloWorldController{
....
....
}
//
1、Controller接收客户端传的参数
1)参数是基本数据类型/包装类型/String
@RequestMapping("test")
public String test(int age){...}
public String test(long id){...}
public String test(boolean flag){...}
public String test(Long id){...}
public String test(String name){...}
注意参数名字要和客户端传的参数名一致,否则需要使用@RequestParam来指定参数名
2)参数是数组类型
@RequestMapping("test")
public String test(int[] age){...}
public String test(long[] id){...}
public String test(boolean[] flag){...}
public String test(Long[] id){...}
public String test(String[] name){...}
注意客户端传值类似于这样:
name=tom&name=lisi
注意客户端传值还可以使用json的方式
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody String[] arr){
for(String s:arr){
System.out.println(s);
}
return "hello";
}
$("#btn").on("click",function(){
var arr = [];
arr.push("hello");
arr.push("world");
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
3)参数是类类型(例如实体类Uesr、Student等)
@RequestMapping("test")
public String test(User user){...}
注意客户端传值类似于这样:
username=tom&password=123&dob=2016-09-25
注意:
1.username/password/dob必须是User中存在的property
2.日期类型需要自定义转换器并在spring中注册
4)类类型的数组
例如:
@RequestMapping("/test")
public String test(@RequestBody User[] users){...}
$("#btn").on("click",function(){
var arr = [];
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
arr.push(json1);
arr.push(json2);
$.ajax({
type:"post",
url:"/test",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
5)List/Set集合
例如1:如果是set集合,直接把List换成Set即可,其他用改
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody List<String> list){...}
$("#btn").on("click",function(){
var arr = [];
arr.push("hello");
arr.push("world");
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
例如2:如果是set集合,直接把List换成Set即可,其他用改
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody List<User> list){....}
$("#btn").on("click",function(){
var arr = [];
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
arr.push(json1);
arr.push(json2);
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
6)Map集合
例如:
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody Map<String,User> map){
for(String s:map.keySet()){
System.out.println(s+" "+map.get(s));
}
return "hello";}
$("#btn").on("click",function(){
var map = {};
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
map[json1.username] = json1;
map[json2.username] = json2;
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(map),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
7)以上任何类型遇到特殊情况下,都可以使用自定义类型转换器:
spring提供的转换器接口:
public interface Converter<S, T> {
T convert(S source);
}
编写完成后需要在spring中注册,例如:
<mvc:annotation-driven conversion-service="formatService"/>
<bean name="formatService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 自己编写的类型转换器,可以有多个 -->
<bean class="com.briup.web.converter.StringToDateConverter"></bean>
</set>
</property>
</bean>
2.SpringMVC中的跳转
1.因为在Controller中的功能处理方法上可以获得到request和response,所以可以像之前servlet中一样,进行服务器内部跳转和客户端重定向
例如:
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
@RequestMapping("/c")
public String testC(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
System.out.println("testC");
//服务器内部跳转到一个页面
//request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
//服务器内部跳转到一个功能处理方法
//request.getRequestDispatcher("/dispatcher/b").forward(request, response);
//客户端重定向到另一个功能处理方法
response.sendRedirect(request.getContextPath()+"/dispatcher/b");
return null;
}
}
2.Controller中可以使用字符串表示服务器内部跳转和客户端重定向
例如:
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/a")
public String testA(){
System.out.println("testA");
//服务器内部跳转到另一个功能处理方法
//return "forward:/dispatcher/b";
//客户端重定向到另一个功能处理方法
//return "redirect:/dispatcher/b";
//服务器内部跳转到一个页面
return "index";
}
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
}
3.Controller中使用ModelAndView进行跳转和重定向
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
@RequestMapping("/d")
public ModelAndView testD() throws ServletException, IOException{
System.out.println("testD");
//服务器内部跳转到另一个功能处理方法
//ModelAndView mv = new ModelAndView("forward:/dispatcher/b");
//客户端重定向到另一个功能处理方法
//ModelAndView mv = new ModelAndView("redirect:/dispatcher/b");
//服务器内部跳转到一个页面
ModelAndView mv = new ModelAndView("index");
return mv;
}
}
3.SpringMVC中的异常处理
在SpringMVC中可以把异常统一进行处理,只需加入以下配置:
<!-- Spring提供的默认的异常解析器,也可以自定义 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->
<property name="defaultErrorView" value="error"></property>
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
<property name="exceptionAttribute" value="ex"></property>
<!-- 定义需要特殊处理的异常,用简单类名或全限定名作为key,异常页名的逻辑视图名作为value -->
<property name="exceptionMappings">
<props>
<prop key="IOException">error_io</prop>
<prop key="java.sql.SQLException">error_sql</prop>
</props>
</property>
</bean>
Controller中代码:
@RequestMapping("/test")
public String test()throws Exception{
//int a = 1/0;
//System.out.println(a);
int a = 1;
if(a==1){
throw new IOException("不好了,出错了!");
}
return "test";
}
页面中:
1.如果使用jsp的脚本显示信息
<!-- 因为spring中修改了异常的默认名字,所以这里是ex -->
<% Exception ex = (Exception)request.getAttribute("ex"); %>
<H2>Exception: <%= ex.getMessage()%></H2>
<P/>
<% ex.printStackTrace(new java.io.PrintWriter(out)); %>
2.如果是EL显示错误信息
<div>${ex }</div>
<div>${ex.message }</div>
异常处理也可以使用注解的形式,注意是这个@ExceptionHandler是要加在需要异常处理的Controller中
@Controller
public class XxxxController {
@RequestMapping("/test")
public String test()throws Exception{
// int a = 1/0;
// System.out.println(a);
int a = 1;
if(a==1){
throw new IOException("你说呢?");
}
return "test";
}
@ExceptionHandler(value={IOException.class,SQLException.class})
public String exp(Exception ex,HttpServletRequest request) {
request.setAttribute("ex", ex);
return "/error.jsp";
}
}
@SessionAttributes(String[] value,Class[] type)
@SessionAttributes(value={},types={})
@SessionAttributes(value={"user"})写在处理器类上面
表示将模型数据中的名字为"user" 的对象存储到会话中,此处value指定将模型数据中的哪些数据(名字进行匹配)存储到会话中,此外还有一个types属性表示模型数据中的哪些类型的对象存储到会话范围内,如果同时指定value和types属性则那些名字和类型都匹配的对象才能存储到会话范围内。
注意,模型数据的作用范围是request级别的,所以一次请求过后,之前模型中的数据就没有了,@SessionAttributes注解可以将当前模型中指定的数据存放到session中,并且还可以从session中把指定数据取出来返回模型中。
1.如果模型里有名字为user的数据,并且使用了@SessionAttributes("user"),那么这个模型中的数据user会被放到session中
2.如果要从模型中拿名字为user的数据,模型中没有,这个时候就拿不到了,但是这个时候使用了@SessionAttributes("user"),那么它会帮我们把数据从session取出来放到模型中
所以处理器类的上面有没有加@SessionAttributes("user")注解,会影响到我们使用下面方式是否能拿到值
@RequestMapping("/session")
public String session(User u) {
System.out.println(u);
return "index";
}
默认只是从模型中拿名字叫user的值,如果加了@SessionAttributes("user")这个注解,还可以拿到session中的user对象
也可以指定用哪个名字拿值,例如:
@RequestMapping("/session")
public String session(@ModelAttribute("my_user") User u) {
System.out.println(u);
return "index";
}
也可以使用SessionStatus对象的方法把@SessionAttributes指定的数据从session中清除掉
@RequestMapping("/session")
public String session(User u,SessionStatus status) {
if(true){
//从session中清除注解中指定的数据
status.setComplete();
}
System.out.println(u);
return "index";
}
2)@Value绑定SpEL表示式
用于将一个SpEL表达式结果映射到到功能处理方法的参数上。
public String test(@Value("#{systemProperties['java.vm.version']}") String jvmVersion){
System.out.println(jvmVersion);
return "index";
}
SpEL表达式的使用,例如:
取名字为stu的bean的name字段的值,这里指的是property
public String test(@Value("#{stu.name}") String username)
对其他bean中某个方法的引用
public String test(@Value("#{stu.sayHello()}") String username)
public String test(@Value("#{stu.sayHello('tom')}") String username)
表达式(?.)可以确保在sayHello()返回不为空的情况下调用toUpperCase()方法,如果返回空那么不继续调用后面的方法
public String test(@Value("#{stu.sayHello()?.toUpperCase()}") String username)
如果要调用的某个类是外部类,而不是spring中定义的bean,使用表达式T()
public String test(@Value("#{T(java.lang.Math).random()}") String username)
3)@InitBinder注解
可以解决类型转换的问题
例如一个表单提交数据给Controller,表单中有日期数据
@Controller
public class InitBinderController{
@RequestMapping(value="/register",method=RequestMethod.GET)
public String registerPage(){
return "register";
}
@RequestMapping(value="/register",method=RequestMethod.POST)
public String register(User user){
System.out.println("user = "+user);
return "index";
}
}
表单提交的时候有一个字符串形式的日期数据"1999-10-23",SpringMVC默认不支持这个格式的转换,所以需要手动配置日期类型的转换,否则会报错。
在这个Controller中加入写一个转换的方法,加上@InitBinder即可
@Controller
public class InitBinderController{
@InitBinder
public void test(WebDataBinder binder){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
//true表示允许为空
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
@RequestMapping(value="/register",method=RequestMethod.GET)
public String registerPage(){
return "register";
}
@RequestMapping(value="/register",method=RequestMethod.POST)
public String register(User user){
System.out.println("user = "+user);
return "index";
}
}
在Spring3中引入了一个Converter接口,它支持从一个任意类型转为另一个任意类型。
例如:
自己编写的转换器代码:
public class StringToDateConverter implements Converter<String, Date>{
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date convert(String str) {
Date date = null;
try {
if(str!=null&&!"".equals(str.trim())){
date = dateFormat.parse(str);
}
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
}
spring的配置文件:例如spring的一个工厂类,产生一个转换服务,同时把我们自己的转换器注入进去,可以有多个
<bean name="formatService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.briup.web.converter.StringToDateConverter"></bean>
</set>
</property>
</bean>
//在mvc标签中指定这个转换服务器
<mvc:annotation-driven conversion-service="formatService"/>
还有另外一种解决日期的方式,就是利用spring提供的一个专门针对日期转换的注解:@DateTimeFormat(pattern="yyyy-MM-dd")
例如:
public class User {
private String username;
private String password;
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date dob;
get/set
}
注意这个时候就不需要我们再写自定义的转换器了,但是如果是其他类型的转换,我们还得需要自己编写自定义的类型转换器
4)@RequestBody注解
可以接收客户端ajax请求中的json数据并且转换为对象,但是只能接收post请求中的数据,因为post请求的数据在请求体中(request-body).
需要引入俩个json相关jar包:
jackson-mapper-asl-1.9.13.jar
jackson-core-asl-1.9.13.jar
注意:在javascript中,json对象和字符串之间的转换:
JSON.stringify(obj)将JSON转为字符串。
JSON.parse(string) 将字符串转为JSON格式;
例如:
处理器中代码:
@RequestMapping(value="/json/update",consumes="application/json",method=RequestMethod.POST)
public void update(@RequestBody User user,Writer out)throws Exception{
System.out.println("user = "+user);
out.write("helloworld");
}
页面js中代码:
注意:http中的Content-Type,在jquery中是contentType
$("#btn").on("click",function(){
var json = {username:"tom",password:"123",dob:"1999-10-27"};
$.ajax({
type:"post",
url:"json/update",
contentType:"application/json",
data:JSON.stringify(json),
dataType:"text",
success:function(data){
console.log("data = "+data);
}
});
});
客户端使用ajax发送json数据给Controller,Controller里面接收json数据并且转换为对象
1.ajax请求发送的时候要指定为post方式
2.ajax请求发送的时候要指定contentType:"application/json"
3.ajax请求发送的时候要把json对象转换为字符串再发送
4.Controller中要使用@RequestBody指定接收数据的参数
5.项目中要引入俩个json相关的jar包
6.如果此ajax请求还希望Controller返回的数据也是json格式的,那么需要在发送ajax请求的时候指定dataType:"json",
7.Controller中的方法要返回json格式的数据给客户端,可以使用@ResponseBody标签 或者 在方法中自己使用response对象获得io流给客户端写回去
注意:
ajax发送请求的时候,请求头中的Content-Type默认值是: application/x-www-form-urlencoded,表示当前请求中如果有数据的话,将会是key=value&key=value的形式
5)@ResponseBody注解
该注解用于将处理器中功能处理方法返回的对象,经过转换为指定格式后,写入到Response对象的body数据区(响应正文).一般返回的数据不是html标签的页面,而是其他某种格式的数据时使用,例如给ajax请求返回json数据.
例如:在@RequestBody的例子中进行修改
处理器中代码:添加了@ResponseBody,修改了方法的返回值
@RequestMapping(value="/json/respbody",consumes="application/json",method=RequestMethod.POST)
@ResponseBody
public User update(@RequestBody User user)throws Exception{
System.out.println("user = "+user);
user.setUsername("张三");
user.setPassword("123");
user.setDob(new Date());
return user;
}
页面js中代码: 注意这里的dataType属性的值
$("#btn").on("click",function(){
var json = {username:"tom",password:"123",dob:"1999-10-27"};
$.ajax({
type:"post",
url:"json/respbody",
contentType:"application/json",
data:JSON.stringify(json),
dataType:"json",
success:function(data){
console.log("data = "+data);
console.log(data.username);
console.log(data.password);
console.log(data.dob);
}
});
});
这里还是会有日期的问题,就是把user对象放入响应正文返回给客户端后,被转换为了json对象,从firebug中可以看出,这个返回的json对象为{"username":"张三","password":"123","dob":1478621620119},它默认把dob这个日期对象转为了一个时间戳
如果我们想按照自己的日期格式进行转换,那么需要这样处理:
自定义一个json的日期类型格式化类:
public class DateJsonSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String formattedDate = formatter.format(value);
jgen.writeString(formattedDate);
}
}
在User类中的getDob方法上添加注解
@JsonSerialize(using=DateJsonSerializer.class)
public Date getDob() {
return dob;
}
@ResponseBody注解可以处理以下常见类型的返回值,如果可以的话还会把返回值转换为json格式字符串
1.单值(基本数据类型和字符串)
2.bean对象(例如User对象、Student对象等,对象中需要有property)
3.数组
4.List/Set集合
5.Map集合
6).@Scope注解
Controller默认情况下和servlet一样也是单例,但是spring提供了一个@Scope注解可以让Controller对象变为非单例,只需在Controller类上面加入@Scope("prototype")即可
可以利用容器的scope="prototype"来保证每一个请求有一个单独的Action来处理, 避免struts中Action的线程安全问题。
例如:
@Controller
@RequestMapping("/hello")
@Scope("prototype")
public class HelloWorldController{
....
....
}
//
1、Controller接收客户端传的参数
1)参数是基本数据类型/包装类型/String
@RequestMapping("test")
public String test(int age){...}
public String test(long id){...}
public String test(boolean flag){...}
public String test(Long id){...}
public String test(String name){...}
注意参数名字要和客户端传的参数名一致,否则需要使用@RequestParam来指定参数名
2)参数是数组类型
@RequestMapping("test")
public String test(int[] age){...}
public String test(long[] id){...}
public String test(boolean[] flag){...}
public String test(Long[] id){...}
public String test(String[] name){...}
注意客户端传值类似于这样:
name=tom&name=lisi
注意客户端传值还可以使用json的方式
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody String[] arr){
for(String s:arr){
System.out.println(s);
}
return "hello";
}
$("#btn").on("click",function(){
var arr = [];
arr.push("hello");
arr.push("world");
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
3)参数是类类型(例如实体类Uesr、Student等)
@RequestMapping("test")
public String test(User user){...}
注意客户端传值类似于这样:
username=tom&password=123&dob=2016-09-25
注意:
1.username/password/dob必须是User中存在的property
2.日期类型需要自定义转换器并在spring中注册
4)类类型的数组
例如:
@RequestMapping("/test")
public String test(@RequestBody User[] users){...}
$("#btn").on("click",function(){
var arr = [];
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
arr.push(json1);
arr.push(json2);
$.ajax({
type:"post",
url:"/test",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
5)List/Set集合
例如1:如果是set集合,直接把List换成Set即可,其他用改
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody List<String> list){...}
$("#btn").on("click",function(){
var arr = [];
arr.push("hello");
arr.push("world");
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
例如2:如果是set集合,直接把List换成Set即可,其他用改
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody List<User> list){....}
$("#btn").on("click",function(){
var arr = [];
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
arr.push(json1);
arr.push(json2);
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
6)Map集合
例如:
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody Map<String,User> map){
for(String s:map.keySet()){
System.out.println(s+" "+map.get(s));
}
return "hello";}
$("#btn").on("click",function(){
var map = {};
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
map[json1.username] = json1;
map[json2.username] = json2;
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(map),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
7)以上任何类型遇到特殊情况下,都可以使用自定义类型转换器:
spring提供的转换器接口:
public interface Converter<S, T> {
T convert(S source);
}
编写完成后需要在spring中注册,例如:
<mvc:annotation-driven conversion-service="formatService"/>
<bean name="formatService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 自己编写的类型转换器,可以有多个 -->
<bean class="com.briup.web.converter.StringToDateConverter"></bean>
</set>
</property>
</bean>
2.SpringMVC中的跳转
1.因为在Controller中的功能处理方法上可以获得到request和response,所以可以像之前servlet中一样,进行服务器内部跳转和客户端重定向
例如:
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
@RequestMapping("/c")
public String testC(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
System.out.println("testC");
//服务器内部跳转到一个页面
//request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
//服务器内部跳转到一个功能处理方法
//request.getRequestDispatcher("/dispatcher/b").forward(request, response);
//客户端重定向到另一个功能处理方法
response.sendRedirect(request.getContextPath()+"/dispatcher/b");
return null;
}
}
2.Controller中可以使用字符串表示服务器内部跳转和客户端重定向
例如:
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/a")
public String testA(){
System.out.println("testA");
//服务器内部跳转到另一个功能处理方法
//return "forward:/dispatcher/b";
//客户端重定向到另一个功能处理方法
//return "redirect:/dispatcher/b";
//服务器内部跳转到一个页面
return "index";
}
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
}
3.Controller中使用ModelAndView进行跳转和重定向
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
@RequestMapping("/d")
public ModelAndView testD() throws ServletException, IOException{
System.out.println("testD");
//服务器内部跳转到另一个功能处理方法
//ModelAndView mv = new ModelAndView("forward:/dispatcher/b");
//客户端重定向到另一个功能处理方法
//ModelAndView mv = new ModelAndView("redirect:/dispatcher/b");
//服务器内部跳转到一个页面
ModelAndView mv = new ModelAndView("index");
return mv;
}
}
3.SpringMVC中的异常处理
在SpringMVC中可以把异常统一进行处理,只需加入以下配置:
<!-- Spring提供的默认的异常解析器,也可以自定义 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->
<property name="defaultErrorView" value="error"></property>
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
<property name="exceptionAttribute" value="ex"></property>
<!-- 定义需要特殊处理的异常,用简单类名或全限定名作为key,异常页名的逻辑视图名作为value -->
<property name="exceptionMappings">
<props>
<prop key="IOException">error_io</prop>
<prop key="java.sql.SQLException">error_sql</prop>
</props>
</property>
</bean>
Controller中代码:
@RequestMapping("/test")
public String test()throws Exception{
//int a = 1/0;
//System.out.println(a);
int a = 1;
if(a==1){
throw new IOException("不好了,出错了!");
}
return "test";
}
页面中:
1.如果使用jsp的脚本显示信息
<!-- 因为spring中修改了异常的默认名字,所以这里是ex -->
<% Exception ex = (Exception)request.getAttribute("ex"); %>
<H2>Exception: <%= ex.getMessage()%></H2>
<P/>
<% ex.printStackTrace(new java.io.PrintWriter(out)); %>
2.如果是EL显示错误信息
<div>${ex }</div>
<div>${ex.message }</div>
异常处理也可以使用注解的形式,注意是这个@ExceptionHandler是要加在需要异常处理的Controller中
@Controller
public class XxxxController {
@RequestMapping("/test")
public String test()throws Exception{
// int a = 1/0;
// System.out.println(a);
int a = 1;
if(a==1){
throw new IOException("你说呢?");
}
return "test";
}
@ExceptionHandler(value={IOException.class,SQLException.class})
public String exp(Exception ex,HttpServletRequest request) {
request.setAttribute("ex", ex);
return "/error.jsp";
}
}