springMVC3

复习:html

 

springmvc框架:前端

         DispatcherServlet前端控制器:接收request,进行responsejava

         HandlerMapping处理器映射器:根据url查找Handler。(能够经过xml配置方式,注解方式)jquery

         HandlerAdapter处理器适配器:根据特定规则去执行Handler,编写Handler时须要按照HandlerAdapter的要求去编写。程序员

         Handler处理器(后端控制器):须要程序员去编写,经常使用注解开发方式。web

                   Handler处理器执行后结果 是ModelAndView,具体开发时Handler返回方法值类型包括 :ModelAndView、String(逻辑视图名)、void(经过在Handler形参中添加request和response,相似原始 servlet开发方式,注意:能够经过指定response响应的结果类型实现json数据输出)ajax

         View resolver视图解析器:根据逻辑视图名生成真正的视图(在springmvc中使用View对象表示)spring

         View视图:jsp页面,仅是数据展现,没有业务逻辑。json

 

注解开发:后端

         使用注解方式的处理器映射器和适配器:

         <!--注解映射器 -->

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

<!--注解适配器 -->

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

 

在实际开发,使用<mvc:annotation-driven>代替上边处理器映射器和适配器配置。

 

@controller注解必需要加,做用标识类是一个Handler处理器。

@requestMapping注解必需要加,做用:

         一、对url和Handler的方法进行映射。

         二、能够窄化请求映射,设置Handler的根路径,url就是根路径+子路径请求方式

         三、能够限制http请求的方法

映射成功后,springmvc框架生成一个Handler对象,对象中只包括 一个映射成功的method。

 

注解开发中参数绑定:

         将request请求过来的key/value的数据(理解一个串),经过转换(参数绑定的一部分),将key/value串转成形参,将转换后的结果传给形参(整个参数绑定过程)。

         springmvc所支持参数绑定:

                   一、默认支持不少类型,HttpServletRequest、response、session、

                            model/modelMap(将模型数据填充到request域)

                   二、支持简单数据类型,整型、字符串、日期。。

                            只要保证request请求的参数名和形参名称一致,自动绑定成功

                            若是request请求的参数名和形参名称不一致,可使用@RequestParam(指定request请求的参数名),@RequestParam加在形参的前边。

                   三、支持pojo类型

                            只要保证request请求的参数名称和pojo中的属性名一致,自动将request请求的参数设置到pojo的属性中。

                  注意:形参中即有pojo类型又有简单类型,参数绑定互不影响。

                   自定义参数绑定:

                            日期类型绑定自定义:

                                     定义的Converter<源类型,目标类型>接口实现类,好比:

                                     Converter<String,Date>表示:将请求的日期数据串转成java中的日期类型。

                                     注意:要转换的目标类型必定和接收的pojo中的属性类型一致。

                                     将定义的Converter实现类注入处处理器适配器中。

<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<!-- conversionService -->
    <bean id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 转换器 -->
        <property name="converters">
            <list>
                <bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
            </list>
        </property>
    </bean>

 

springmvc和struts2区别:

springmvc面向方法开发的(更接近service接口的开发方式),struts2面向类开发。

springmvc能够单例开发,struts2只能是多例开发。

 

1       包装类型pojo参数绑定

 

1.1      需求

         商品查询controller方法中实现商品查询条件传入。

 

1.2      实现方法

第一种方法:在形参中 添加HttpServletRequest request参数,经过request接收查询条件参数。

第二种方法:在形参中让包装类型的pojo接收查询条件参数。

         分析:

         页面传参数的特色:复杂,多样性。条件包括 :用户帐号、商品编号、订单信息。。。

         若是将用户帐号、商品编号、订单信息等放在简单pojo(属性是简单类型)中,pojo类属性比较多,比较乱。

         建议使用包装类型的pojo,pojo中属性是pojo。

        

1.3      页面参数和controller方法形参定义

 

页面参数:

 

         商品名称:<input name="itemsCustom.name" />

         注意:itemsCustom和包装pojo中的属性一致便可。

 

controller方法形参:

   

      public ModelAndView queryItems(HttpServletRequest request,ItemsQueryVo itemsQueryVo) throws Exception

 

2       集合类型绑定

 

2.1      数组绑定

 

2.1.1     需求

商品批量删除,用户在页面选择多个商品,批量删除。

 

2.1.2     表现层实现

关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。

 

controller方法定义:

 

 

 

3.1      list绑定

3.1.1     需求

一般在须要批量提交数据时,将提交的数据绑定到list<pojo>中,好比:成绩录入(录入多门课成绩,批量提交),

本例子需求:批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中。

 

3.1.2     表现层实现

controller方法定义:

         一、进入批量商品修改页面(页面样式参考商品列表实现)

         二、批量修改商品提交

         使用List接收页面提交的批量数据,经过包装pojo接收,在包装pojo中定义list<pojo>属性

 

 

页面定义:

 

3.3      map绑定

也经过在包装pojo中定义map类型属性。

 

在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。

包装类中定义Map对象以下:

 

Public class QueryVo {
private Map<String, Object> itemInfo = new HashMap<String, Object>();
  //get/set方法..
}

 

 

页面定义以下:

 

<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>

 

Contrller方法定义以下:

 

public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}

 

 

1       springmvc校验

 

1.1      校验理解

 

项目中,一般使用较可能是前端的校验,好比页面中js校验。对于安全要求较高点建议在服务端进行校验。

 

服务端校验:

         控制层conroller:校验页面请求的参数的合法性。在服务端控制层conroller校验,不区分客户端类型(浏览器、手机客户端、远程调用)

         业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。

         持久层dao:通常是不校验的。

 

1.2      springmvc校验需求

 

springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。

 

校验思路:

         页面提交请求的参数,请求到controller方法中,使用validation进行校验。若是校验出错,将错误信息展现到页面。

具体需求:

         商品修改,添加校验(校验商品名称长度,生产日期的非空校验),若是校验出错,在商品修改页面显示错误信息。

 

1.3      环境准备

hibernate的校验框架validation所须要jar包:

 

1.4     配置校验器

1.5      校验器注入处处理器适配器中

 

 

 

 

1.6      在pojo中添加校验规则

在ItemsCustom.java中添加校验规则:

 

1.7      CustomValidationMessages.properties

 

在CustomValidationMessages.properties配置校验错误信息:

 

 

 

1.8     捕获校验错误信息

 

在须要校验的pojo前边添加@Validated,在须要校验的pojo后边添加BindingResult bindingResult接收校验出错信息

注意:@ValidatedBindingResult bindingResult是配对出现,而且形参顺序是固定的(一前一后)。

 

1.9     在页面显示校验错误信息

 

在controller中将错误信息传到页面便可。

 

 

 

 

1.1      分组校验

1.1.1     需求

在pojo中定义校验规则,而pojo是被多个 controller所共用,当不一样的controller方法对同一个pojo进行校验,可是每一个controller方法须要不一样的校验。

 

解决方法:

定义多个校验分组(实际上是一个java接口),分组中定义有哪些规则

每一个controller方法使用不一样的校验分组

 

 

1.1.2     校验分组 

 

1.1.1     在校验规则中添加分组

 

 

1.1.1     在controller方法使用指定分组的校验

 

 

 

1       数据回显

1.1      什么数据回显

提交后,若是出现错误,将刚才提交的数据回显到刚才的提交页面。

 

1.2      pojo数据回显方法

 

一、springmvc默认对pojo数据进行回显。

pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)

 

使用@ModelAttribute指定pojo回显到页面在request中的key

 

二、@ModelAttribute还能够将方法的返回值传到页面

 

在商品查询列表页面,经过商品类型查询商品信息。

在controller中定义商品类型查询方法,最终将商品类型传到页面。

 

页面上能够获得itemTypes数据

 

三、使用最简单方法使用model,能够不用@ModelAttribute

 

1.3      简单类型数据回显

 

使用最简单方法使用model。

 

model.addAttribute("id", id);

 

 

1       异常处理

1.1      异常处理思路

 

系统中异常包括两类:预期异常和运行时异常RuntimeException,前者经过捕获异常从而获取异常信息,后者主要经过规范代码开发、测试经过手段减小运行时异常的发生。

         系统的dao、service、controller出现都经过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,以下图:

 

springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。

 

1.2      自定义异常类

 

对不一样的异常类型定义异常类,继承Exception。

 

1.3      全局异常处理器

 

思路:

         系统遇到异常,在程序中手动抛出,dao抛给service、service给controller、controller抛给前端控制器,前端控制器调用全局异常处理器。

         全局异常处理器处理思路:

                  解析出异常类型

                  若是该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展现

                  若是该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)

 

springmvc提供一个HandlerExceptionResolver接口

 

@Override
    public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex) {
        //handler就是处理器适配器要执行Handler对象(只有method)
        
//        解析出异常类型
//        若是该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展现
//        String message = null;
//        if(ex instanceof CustomException){
//            message = ((CustomException)ex).getMessage();
//        }else{
////            若是该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
//            message="未知错误";
//        }
        
        //上边代码变为
        CustomException customException = null;
        if(ex instanceof CustomException){
            customException = (CustomException)ex;
        }else{
            customException = new CustomException("未知错误");
        }
        
        //错误信息
        String message = customException.getMessage();
        
        
        ModelAndView modelAndView = new ModelAndView();
        
        //将错误信息传到页面
        modelAndView.addObject("message", message);
        
        //指向错误页面
        modelAndView.setViewName("error");

        
        return modelAndView;
    }

1.4      错误页面

 

1.5      在springmvc.xml配置全局异常处理器

 

1.6      异常测试

 

在controller、service、dao中任意一处须要手动抛出异常。

若是是程序中手动抛出的异常,在错误页面中显示自定义的异常信息,若是不是手动抛出异常说明是一个运行时异常,在错误页面只显示“未知错误”。

 

在商品修改的controller方法中抛出异常 .

 

在service接口中抛出异常:

 

 

若是与业务功能相关的异常,建议在service中抛出异常。

与业务功能没有关系的异常,建议在controller中抛出。

 

上边的功能,建议在service中抛出异常。

 

1       上传图片

 

1.1      需求

在修改商品页面,添加上传商品图片功能。

 

1.2      springmvc中对多部件类型解析

 

在 页面form中提交enctype="multipart/form-data"的数据时,须要springmvc对multipart类型的数据进行解析。

 

在springmvc.xml中配置multipart类型解析器。

 

 

 

 

1.3      加入上传图片的jar

上边的解析内部使用下边的jar进行图片上传。

 

 

 

1.4      建立图片虚拟 目录 存储图片

经过图形界面配置:

 

 

 

也能够直接修改tomcat的配置:

 

在conf/server.xml文件,添加虚拟 目录 :

 

 

 

 

注意:在图片虚拟目录 中,必定将图片目录分级建立(提升i/o性能),通常咱们采用按日期(年、月、日)进行分级建立。

 

1.5      上传图片代码

1.5.1     页面

 

 

 

 

1.5.2     controller方法

修改:商品修改controller方法:

 

 

 

1       json数据交互

 

1.1      为何要进行json数据交互

 

json数据格式在接口调用中、html页面中较经常使用,json格式比较简单,解析还比较方便。

好比:webservice接口,传输json数据.

 

1.2      springmvc进行json交互

 

 

 

一、请求json、输出json,要求请求的是json串,因此在前端页面中须要将请求的内容转成json,不太方便。

 

二、请求key/value、输出json。此方法比较经常使用。

 

1.3      环境准备

 

1.3.1     加载json转的jar包

springmvc中使用jackson的包进行json转换(@requestBody和@responseBody使用下边的包进行json转),以下:

 

 

 

1.3.2     配置json转换器

 

在注解适配器中加入messageConverters

 

<!--注解适配器 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
        <list>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
        </list>
        </property>
    </bean>

注意:若是使用<mvc:annotation-driven /> 则不用定义上边的内容。

1.4      json交互测试

 

1.4.1     输入json串,输出是json串

1.4.1.1              jsp页面

使用jquery的ajax提交json串,对输出的json结果进行解析。

 

1.4.1.2              controller

 

1.4.1.3              测试结果

 

 

1.4.2     输入key/value,输出是json串

 

1.4.2.1              jsp页面

使用jquery的ajax提交key/value串,对输出的json结果进行解析。

 

 

1.4.2.2              controller

 

 

1.4.2.3              测试

 

 

 

1       RESTful支持

 

1.1      什么是RESTful

RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,因此正获得愈来愈多网站的采用。

 

RESTful(即Representational State Transfer的缩写)实际上是一个开发理念,是对http的很好的诠释。

 

 

一、对url进行规范,写RESTful格式的url

 

非REST的url:http://...../queryItems.action?id=001&type=T01

REST的url风格:http://..../items/001

         特色:url简洁,将参数经过url传到服务端

二、http的方法规范

不论是删除、添加、更新。。使用url是一致的,若是进行删除,须要设置http的方法为delete,同理添加。。。

 

后台controller方法:判断http方法,若是是delete执行删除,若是是post执行添加。

 

三、对http的contentType规范

请求时指定contentType,要json数据,设置成json格式的type。。

 

1.2      REST的例子

1.2.1     需求

查询商品信息,返回json数据。

 

1.2.2     controller

定义方法,进行url映射使用REST风格的url,将查询商品信息的id传入controller .

 

输出json使用@ResponseBody将java对象输出json。

 

@RequestMapping(value="/ itemsView/{id}"):{×××}占位符,请求的URL能够是“/viewItems/1”或“/viewItems/2”,经过在方法中使用@PathVariable获取{×××}中的×××变量。

@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。

若是RequestMapping中表示为"/ itemsView /{id}",id和形参名称一致,@PathVariable不用指定名称。

 

1.2.3     REST方法的前端控制器配置

 

在web.xml配置:

 

 

 

1.3      对静态资源的解析

 

配置前端控制器的url-parttern中指定/,对静态资源的解析出现问题:

 

 

 

在springmvc.xml中添加静态资源解析方法。

 

 

1       拦截器

1.1      拦截定义

 

定义拦截器,实现HandlerInterceptor接口。接口中提供三个方法。

 

public class HandlerInterceptor1 implements HandlerInterceptor {

    
    //进入 Handler方法以前执行
    //用于身份认证、身份受权
    //好比身份认证,若是认证经过表示当前用户没有登录,须要此方法拦截再也不向下执行
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        
        //return false表示拦截,不向下执行
        //return true表示放行
        return false;
    }

    //进入Handler方法以后,返回modelAndView以前执行
    //应用场景从modelAndView出发:将公用的模型数据(好比菜单导航)在这里传到视图,也能够在这里统一指定视图
    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        
        
    }

    //执行Handler完成执行此方法
    //应用场景:统一异常处理,统一日志处理
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        
        
    }

}

 

1.2      拦截器配置

 

 

1.2.1     针对HandlerMapping配置

springmvc拦截器针对HandlerMapping进行拦截设置,若是在某个HandlerMapping中配置拦截,通过该 HandlerMapping映射成功的handler最终使用该 拦截器。

<bean
    class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    <property name="interceptors">
        <list>
            <ref bean="handlerInterceptor1"/>
            <ref bean="handlerInterceptor2"/>
        </list>
    </property>
</bean>
    <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
    <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

 

通常不推荐使用。

 

1.2.2     相似全局的拦截器

springmvc配置相似全局的拦截器,springmvc框架将配置的相似全局的拦截器注入到每一个HandlerMapping中。

 

 

1.3      拦截测试

1.3.1     测试需求

测试多个拦截器各各方法执行时机。

 

 

1.3.2     编写两个拦截

 

1.3.3     两个拦截器都放行

HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle

HandlerInterceptor2...postHandle
HandlerInterceptor1...postHandle

HandlerInterceptor2...afterCompletion
HandlerInterceptor1...afterCompletion

 

 

总结:

preHandle方法按顺序执行,

postHandleafterCompletion按拦截器配置的逆向顺序执行。

 

1.3.4     拦截器1放行,拦截器2不放行

HandlerInterceptor1...preHandle

HandlerInterceptor2...preHandle

HandlerInterceptor1...afterCompletion

 

 

总结:

拦截器1放行,拦截器2 preHandle才会执行。

拦截器2 preHandle不放行,拦截器2 postHandle和afterCompletion不会执行。

只要有一个拦截器不放行,postHandle不会执行。

 

1.3.1      拦截器1不放行,拦截器2不放行

HandlerInterceptor1...preHandle

 

拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。

拦截器1 preHandle不放行,拦截器2不执行。

 

 

1.3.2     小结

 

根据测试结果,对拦截器应用。

 

好比:统一日志处理拦截器,须要该 拦截器preHandle必定要放行,且将它放在拦截器连接中第一个位置。

 

好比:登录认证拦截器,放在拦截器连接中第一个位置。权限校验拦截器,放在登录认证拦截器以后。(由于登录经过后才校验权限)

 

1.4      拦截器应用(实现登录认证)

 

1.4.1     需求

 

一、用户请求url

二、拦截器进行拦截校验

         若是请求的url是公开地址(无需登录便可访问的url),让放行

         若是用户session 不存在跳转到登录页面

         若是用户session存在放行,继续操做。

 

1.4.2     登录controller方法

 

@Controller
public class LoginController {

    // 登录
    @RequestMapping("/login")
    public String login(HttpSession session, String username, String password)
            throws Exception {

        // 调用service进行用户身份验证
        // ...

        // 在session中保存用户身份信息
        session.setAttribute("username", username);
        // 重定向到商品列表页面
        return "redirect:/items/queryItems.action";
    }

    // 退出
    @RequestMapping("/logout")
    public String logout(HttpSession session) throws Exception {

        // 清除session
        session.invalidate();

        // 重定向到商品列表页面
        return "redirect:/items/queryItems.action";
    }

}

 

1.4.3     登录认证拦截实现

 

1.4.3.1              代码实现

 

public class LoginInterceptor implements HandlerInterceptor {

    
    //进入 Handler方法以前执行
    //用于身份认证、身份受权
    //好比身份认证,若是认证经过表示当前用户没有登录,须要此方法拦截再也不向下执行
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        
        //获取请求的url
        String url = request.getRequestURI();
        //判断url是不是公开 地址(实际使用时将公开 地址配置配置文件中)
        //这里公开地址是登录提交的地址
        if(url.indexOf("login.action")>=0){
            //若是进行登录提交,放行
            return true;
        }
        
        //判断session
        HttpSession session  = request.getSession();
        //从session中取出用户身份信息
        String username = (String) session.getAttribute("username");
        
        if(username != null){
            //身份存在,放行
            return true;
        }
        
        //执行这里表示用户身份须要认证,跳转登录页面
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        
        //return false表示拦截,不向下执行
        //return true表示放行
        return false;
    }

 

1.4.3.2              拦截器配置

 

相关文章
相关标签/搜索