SpringMVC系列笔记(四)

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";  
        }  
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值