Java框架之Spring MVC(二)

1、Spring MVC 验证css

JSR 303 是ajvaEE6 中的一项子规范 ,叫 Bean Validation 用于对javaBean中的字段进行校验。html

官方的参考实现是: Hibernate Validator ,此实现和 Hibernate ORM 没有任何关系  //http://hibernate.org/validator前端

Spring 3.x 也大力支持     JSR 303,使用的是  Hibernate Validatorjava

1) 导包web

4.3.1.Final 版本为例ajax

// jboss-logging-3.1.0.CR2.jarspring

hibernate-validator-4.3.1.Final.jarjson

jboss-logging-3.1.0.jar、api

validation-api-1.0.0.GA.jar缓存

2) 配置文件

<mvc:annotation-driven validator="validator" />
    
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
                <property name="providerClass"  value="org.hibernate.validator.HibernateValidator"/>
                <property name="validationMessageSource" ref="validatemessageSource"/> //不设置则默认为classpath下的 ValidationMessages.properties
</bean>
               
<bean id="validatemessageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
               <property name="basename" value="classpath:validatemessages"/>  //配置验证信息资源文件的路径
               <property name="fileEncodings" value="utf-8"/>  
               <property name="cacheSeconds" value="120"/>   //缓存时间
</bean>

3) 建立校验信息用的资源文件,本例在类路径(src或config)下直接建立便可

validatemessages.properties 内容

name.not.empty=名字不能为空

age.not.inrange=年龄要在合适的范围内

email.not.correct=邮箱格式不正确

email.not.empty=邮箱不能为空

4) 在实体类上,添加校验

 public class UserInfo {
                    private  int id;
                    
                    @NotNull(message="用户名不能为 null")
                    @NotEmpty(message="{name.not.empty}")
                    @Pattern(regexp="13\\d{9}",message="用户名是按手机验证的格式不对")
                    private String userName;   
                    
                    @Size(min=3,max=6,message="{password.not.inrange}")
                    private String password;
                    
                    @NotEmpty(message="{email.not.empty}")
                    @Email(message="{email.not.correct}")
                    private String note;
                    private String aihao;
                        
            //也能够将规则添在get 方法上    

5) 控制器 

//在添加用户这个请求提交上来的时候
@RequestMapping(value="/addUser" ,method=RequestMethod.POST)
public String addUser(Model model, @Valid UserInfo user,BindingResult bResult){
                        if(bResult.hasErrors()){
                            List<ObjectError> errorList=    bResult.getAllErrors();
                            for(ObjectError e:errorList){
                                System.out.println(e.getDefaultMessage());
                            }
                            
                            model.addAttribute("errorList",errorList); //把错误信息传到前台
                            return "user_add";
                        }
                        
                        else{
                            return "success";
                        }
                    } 

说明: BindingResult 是Errors的子类

@Valid  和  BindingResult 的位置不要写反

@Valid  写成了 @Validated 实测也能够

6) 前端页面

<c:forEach var="e" items="${errorList }">
                       ${e.defaultMessage}
                       </c:forEach>
                                   
                   <form action="${pageContext.request.contextPath }/addUser" method="post">
                   帐号:    <input type="text" name="userName"  /> 
                   密码:  <input type="text" name="password"  /> 
                   备注:  <input type="text" name="note" /> 
                          <input type=submit value="提交" />
                   </form>

例子 如何详细的显示出错信息

新建页面 user_add_validate.jsp

 <%@ taglib uri="http://www.springframework.org/tags/form" prefix="x" %>
         <x:form method="post" action="${pageContext.request.contextPath }/addUser">
           帐号:<x:input path="userName" /> <x:errors path="userName" /><br>
            密码:<x:input path="password" /> <x:errors path="password" /> <br>
           备注:<x:input path="note" /><x:errors path="note" /> <br>
           <input type=submit value="提交" />
    </x:form>

问题:

1) 若是直接访问  user_add_validate.jsp 出现错误 

//java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?

缘由是Spring环境没初始化

<context-param>    
<param-name>contextConfigLocation</param-name>    
<param-value>classpath:springmvc-servlet.xml</param-value>    
</context-param>
<listener>    
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

2) 须要指定  modelAttribute="user" 这个属性

<x:form method="post" action="${pageContext.request.contextPath }/addUser" modelAttribute="user"  >
//上面也能够写成 commandName="user"

3) 不能直接访问 user_add_validate.jsp 要这样:

@RequestMapping(value="/addUser",method=RequestMethod.GET)
public String addUser(@ModelAttribute("user") UserInfo user){   //@ModelAttribute("user") 必加
                return "user_add_validate";
}

4) 添加用户的方法要以下

@RequestMapping(value="/addUser" ,method=RequestMethod.POST)
                public String addUser( @ModelAttribute("user") @Valid UserInfo user,BindingResult bResult){
                    if(bResult.hasErrors()){
                        return "user_add_validate";
                    }
                    else{
                        return "success";
                    }
                } 

附加:

分组校验

问题: 当一个pojo类被多个业务方法使用,但它的验证规则不一样,如何处理?

能够采用分组校验

1)定义分组 (其实就是定义接口,空接口就能够,一个接口就是一个分组)

public interface IVG1, IVG2

2)在pojo类上指定校验属于哪一个分组

public class UserInfo(
@NotEmpty(message="用户名不能为 null",groups={IVG1.class})

@Size(min=3,max=6,message="{password.not.inrange}",groups={IVG1.class,IVG2.class})
private String password;
                 ...
            }

3)在业务方法上指定验证的时候使用哪一个分组

@RequestMapping(value="/addUser" ,method=RequestMethod.POST)
public String addUser( @ModelAttribute("user") @Validated(value=IVG1.class) UserInfo user,BindingResult bResult){
                    if(bResult.hasErrors()){
                        return "user_add_validate";
                    }
                    else{
                        return "success";
                    }
                } 
//注意,用的是  @Validated 注解 不是 @Valid

2、Spring MVC 数据的回显

(其实上例就是带数据回显的)

pojo类型的数据回显

@RequestMapping(value="/addUser" ,method=RequestMethod.POST)
public String addUser( @ModelAttribute("user") UserInfo user){
                      ....
                    } 

 页面的 from上也要加 modelAttribute 或 commondName

<x:form action="${pageContext.request.contextPath }/test" method="post" modelAttribute="user">
<x:input path="userName" />  //注意,要回显示的数据必须用 这样的标签
<x:input path="password" />
</x:form>

 对于简单类型

用 model.addAttribute(...)  便可

3、Spring MVC 异常处理

SpringMVC 提供全局异常处理器进行统一的异常处理

1) 在controller(Action)内部处理异常

-- login.jsp

 <form action="user/login" method="post" >
                        帐号:<input type="text" name="userName" /> 
                        密码:<input type="text" name="password" />
                        <input type="submit" />

-- 自定义异常类 //不定义也能够

public class MyException extends Exception{
                        private String msg;
                        public MyException(String msg){
                            super(msg);
                            this.msg=msg;
                        }
                        
                        public void writeLog(){
                            System.out.println("---异常信息"+this.msg+"已经记录-");
                        }
                    
                    }

-- action 中的处理

@RequestMapping(value="/login")
public String login(HttpSession session,String userName,String password) throws MyException {
                        UserInfo user=new UserDao().getLoginUser(userName, password);
                        if(user==null){
                            throw new MyException("用户登陆失败");  //若是登陆失败,抛出异常
                            }
                            session.setAttribute("user", user);
                            return "success";
                        }
                        
                        @ExceptionHandler(value={MyException.class}) //这里是进行异常处理的地方
                        public String exectionProcessAAA(MyException e,HttpServletRequest request){
                        request.setAttribute("e_msg", e.getMessage());
                        e.writeLog();
                        return "error" ;  //全局的一个异常处理页面    
                    }

2) 全局异常处理

--在配置文件中加入配置

<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">     
<property name="exceptionMappings">     
    <props>     
    <prop key="cat.beans.MyException">error_process_1</prop>   //能够看到,能够为每种异常指定一个result视图
    <prop key="java.lang.Exception">error_process_2</prop>     
    <prop key="java.lang.Throwable">error_process_3</prop>     
    </props>     
</property>     
</bean>  

在异常处理页面

${exception.message}  //这样便可取出异常信息

4、Spring MVC 文件上传

1) 单文件上传

== 在配置文件中

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
                 <property name="defaultEncoding" value="UTF-8" />  //这里面的这些属性能够不用,一个都不写也不会出错
                 <property name="maxUploadSize" value="5400000" />
                 <property name="uploadTempDir" value="uploadTempDir" />
</bean>

== 页面

<form method="post"  action="${pageContext.request.contextPath }/addUserWithImg"    enctype="multipart/form-data" >  
                   <input name="userName" /> 
                   <input name="password"/>  
                   <input name="note"/>  
                   <input type="file" name=upfile />  //注意,这个名字
                   <input type="submit" >
           </form> 

 == 控制层

@RequestMapping(value="/addUserWithImg",method=RequestMethod.POST)
public String addUserWithImg(UserInfo user,MultipartFile upfile /*注意这个名字要和表单元素同名*/ ,HttpServletRequest request ) 
throws IllegalStateException, IOException{ System.out.println(upfile); System.out.println("contentType:"+upfile.getContentType()); //image/pjepg System.out.println("name:"+upfile.getName()); //photo System.out.println("getOriginalFilename:"+upfile.getOriginalFilename()); //zhangsan.jpg System.out.println("getSize:"+upfile.getSize()); new UserDao().addUser(user); String path=request.getServletContext().getRealPath("/upload_files"); File targetFile=new File(path, upfile.getOriginalFilename()); upfile.transferTo(targetFile); return "success"; }

2) 多文件上传  

<form method="post"  action="${pageContext.request.contextPath }/addUserWithMultImg"    enctype="multipart/form-data" >  
                       <input name="userName" /> 
                       <input name="password"/>  
                       <input name="note"/>  
                       
                       <input type="file" name=upfiles />
                       <input type="file" name=upfiles />
                       <input type="file" name=upfiles />
                       <input type="file" name=upfiles />
                       
                       <input type="submit" >
               </form> 
//注意要加上  @RequestParam
public String ddUserWithMultImg(UserInfo user,@RequestParam("upfiles") MultipartFile [] upfiles ,HttpServletRequest request )
throws IllegalStateException, IOException{ new UserDao().addUser(user); String path=request.getServletContext().getRealPath("/upload_files"); for(MultipartFile f:upfiles){ if(!f.isEmpty()){ File targetFile=new File(path, f.getOriginalFilename()); f.transferTo(targetFile); } } return "success"; }

5、Spring MVC 资源文件的引入

在配置文件中:

<mvc:resources location="/images/" mapping="/images/**" />
<mvc:resources location="/css/" mapping="css/**" />
//也能够放在一个文件夹中,统一的引入,如
<mvc:resources location="/resource/" mapping="resource/**" />

6、Spring MVC 关于json数据处理

1) 传统方式的 ajax访问和响应

//请求发起页面  ajax_test.jsp
$(function(){
$("#btn1").click(function(){
$.ajax({
        url:"testAjax",
        type:"post",
        data:{userName:'admin',password:'123'},
        async:false,
        cache:false,
        dataType:"json",
        success:function(data){
        //alert(data);
        alert(data.id);
        alert(data.note);
                            }
                        });
                    });
                });
        
@RequestMapping("/testAjax")
public void testAjax(HttpServletRequest request,HttpServletResponse response) throws IOException{
                String userName=request.getParameter("userName");
                String password=request.getParameter("password");
                System.out.println(userName+":"+password);
                
                response.setContentType("text/html;charset=utf-8");
            //response.getWriter().print("这是普通数据");
                
                String jsonStr="{\"note\":\"这是备注\",\"id\":\"90\"}";
                response.getWriter().print(jsonStr);
            }

附注: 

@RequestBody 用来处理application/json 类型的请求内容

使用 @ResponseBody 的方式返回json 格式的数据

要导入包 spring mvc 4.1.4

jackson-annotations-2.4.4.jar、

jackson-core-2.4.4.jar、

jackson-databind-2.4.4.jar。

附 3.1 用的是

jackson-core-asl-1.9.11.jar 

jackson-mapper-asl-1.9.11.jar

//例一 从服务端查询出一个userInfo对象返回
             //服务端
                @RequestMapping("/testAjax2") @ResponseBody  //这里用 @ResponseBody 注解声明返回json数据
                public UserInfo testAjax2(UserInfo u) {
                    UserInfo user=new UserDao().getLoginUser(u.getUserName(), u.getPassword());
                    return user;
                }
             //客户端
                 $.ajax({
                    url:"testAjax2",
                    type:"post",
                    data:{userName:'aaa',password:'aaa'},  //在服务端,用的是pojo类型的对象接收的参数
                    async:false,
                    cache:false,
                    dataType:"json",
                       success:function(data){
                        alert(data.id);
                        alert(data.note);
                    }
                });
//例二 从服务端查询一组对象返回
                @RequestMapping("/testAjax3") @ResponseBody
                public List<UserInfo> testAjax2() {
                    List<UserInfo> userList=new UserDao().getAllUser();
                    return userList;
                }
                                        
              $("#btn3").click(function(){
                        $.ajax({
                            url:"testAjax3",
                            type:"post",
            
                            async:false,
                            cache:false,
                            dataType:"json",
                            success:function(userList){ //从服务端返回的是一组对象
                                $.each(userList,function(key,user){
                                    $("#div1").append(user.id +"-"+user.userName+"-"+user.password+"<br />");
                                });
                            }
                        });
                    });

7、Spring MVC中 RESTful 风格

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的,HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的做者之1、Apache基金会的第一任主席。长期以来,软件研究主要关注软件设计的分类、设计方法的演化,不多客观地评估不一样的设计选择对系统行为的影响。而相反地,网络研究主要关注系统之间通讯行为的细节、如何改进特定通讯机制的表现,经常忽视了一个事实,那就是改变应用程序的互动风格比改变互动协议,对总体表现有更大的影响。我这篇文章的写做目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,获得一个功能强、性能好、适宜通讯的架构

REST,即Representational State Transfer的缩写。咱们对这个词组的翻译是"表现层状态转化"。 

若是一个架构符合REST原则,就称它为RESTful架构。关于 Representational State Transfer (表现层状态转化) 的理解。

1)REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。

网络上的一个具体信息,能够用一个URI(统一资源定位符)指向它

2) Representation 表现层

"资源"是一种信息实体,它能够有多种外在表现形式。咱们把"资源"具体呈现出来的形式,叫作它的"表现层"(Representation)。

好比,文本能够用txt格式表现,也能够用HTML格式、XML格式

URI只表明资源的实体,不表明它的形式。严格地说,有些网址最后的".html"后缀名是没必要要的 由于这个后缀名表示格式,属于 "表现层" 范畴,而URI应该只表明"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。

3) State Transfer 状态转化

HTTP协议,是一个无状态协议。这意味着,全部的状态都保存在服务器端。所以,若是客户端想要操做服务器,必须经过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是创建在表现层之上的,因此就是"表现层状态转化"。客户端用到的手段,只能是HTTP协议。具体来讲,就是HTTP协议里面,四个表示操做方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操做:

GET用来获取资源,POST用来新建资源(也能够用于更新资源),PUT用来更新资源,DELETE用来删除资源。

综合上面的解释,咱们总结一下什么是RESTful架构:

(1)每个URI表明一种资源;

(2)客户端和服务器之间,传递这种资源的某种表现层;

(3)客户端经过四个HTTP动词,对服务器端资源进行操做,实现"表现层状态转化"。

http://localhost:8080/myweb/userAction_show.action?id=5  

rest 风格 

http://www.douban.com/photos/album/49432287/   这是豆瓣上的url rest风格

查询用户

http://localhost:8080/myweb/user/5 

删除用户

http://localhost:8080/myweb/user/5/delete

//例子

@RequestMapping("/get_user/{id}/{flag}") public String getUser(@PathVariable("id") int idAAA, @PathVariable("flag") String flagAAA){ System.out.println(idAAA +":"+flagAAA); return "success"; }

 请求的url

http://localhost:8080/springmvc-03/get_user/10/search

若是不传  PathVariable 指定的参数,会报404

8、Spring MVC 拦截器

SpringMVC 中的Interceptor 拦截器也是至关重要和至关有用的,它的主要做用是拦截用户的请求并进行相应的处理。好比经过它来进行权限验证,或者是来判断用户是否登录,或者是像12306 那样子判断当前时间是不是购票时间。

方式一: 用实现 HandlerInterceptor  接口的方式

方式二: 继承抽象类HandlerInterceptorAdapter  (Spring 提供的类,它实现了 HandlerInterceptor)

方式三: 实现WebRequestInterceptor 接口或继承实现了该接口的类

例子:

1) 拦截器声明

public class MyInterceptor implements HandlerInterceptor {
            /*==在Controller 方法被调用以前执行,通常用来进行身份验证,受权等
              == SpringMVC中的Interceptor 拦截器是链式的,能够同时存在多个Interceptor,并根据声明的先后顺序依次执行
              == 并且全部的Interceptor中的 preHandle 方法都会在 Controller方法调用以前调用
              == SpringMVC的这种Interceptor链式结构也是能够进行中断的,preHandle的返回值为false的时候整个请求就结束了 */
            public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
                    Object arg2) throws Exception {
                System.out.println("preHandle");
                return true;
            }
        
            /* 通常在处理公用的模型数据,统一指定视图等操做的时候用
             == 在preHandle方法返回值为true的时候才会执行。
             == 它的执行时间是在是在Controller的方法调用以后,DispatcherServlet进行视图的渲染以前执行
             == 能够对ModelAndView进行操做。
             == 这个方法的链式结构跟正常访问的方向是相反的,也就是说先声明的Interceptor拦截器该方法反而会后调用,这跟Struts2里面的拦截器的执行过程有点像          
            */
            public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
                    Object arg2, ModelAndView modelAndView) throws Exception {
                System.out.println("postHandle");    
            }
            
            /*
             == 在preHandle方法返回值为true的时候才会执行。
             == 该方法将在整个请求完成以后,也就是DispatcherServlet渲染了视图执行,  
             == 这个方法的主要做用是用于清理资源的,统一的日志及异常处理等    */
            public void afterCompletion(HttpServletRequest arg0,
                    HttpServletResponse arg1, Object arg2, Exception arg3)
                    throws Exception {
                System.out.println("afterCompletion");    
            }
        }

 2) 在配置文件中加入配置

<mvc:interceptors>   
//若是有 多个拦截器,顺序执行   
<mvc:interceptor>   
// 若是不配置或/*,将拦截全部的Controller
<mvc:mapping path="/searchall_forupdate" /> path 配置拦的是请求的url
//<mvc:mapping path="/**" /> 全部的url包扩子url 
<bean class="cat.interceptor.MyInterceptor"></bean>   
</mvc:interceptor>   

</mvc:interceptors> 
//例子,验证用户是否登陆
        public class MySessionInterceptor implements HandlerInterceptor {
                    public void afterCompletion(HttpServletRequest arg0,
                            HttpServletResponse arg1, Object arg2, Exception arg3)
                            throws Exception {    }
                
                
                    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
                            Object handler, ModelAndView arg3) throws Exception {}
                
                
                    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                            Object obj) throws Exception {
                        String url=request.getRequestURI();
                        System.out.println(url);
                        if(url.contains("login")){  //若是用户发的是登陆的请求,则直接放行
                            return true;
                        }
                        else{
                            UserInfo user=(UserInfo)request.getSession().getAttribute("user");
                            if(user!=null){
                                return true;
                            }
                            else{
                                request.setAttribute("msg", "请登陆");
                                request.getRequestDispatcher("login.jsp").forward(request, response);
                                return false;
                            }
                        }
                    }

上面的拦截器的配置文件

<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
    <bean class="cat.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
                    
<mvc:interceptor>
<mvc:mapping path="/**" />
    <bean class="cat.interceptor.MySessionInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>  
相关文章
相关标签/搜索