简介

springmvc与struts2不同

  1. springmvc的入口是一个servlet即前端控制器,Servlet比过滤器快,而struts2入口是一个filter过滤器。
  2. springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
  3. Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面。Jsp视图解析器默认使用jstl。

运行速度:
Struts2是多例,请求来了以后,struts2创建多少个对象:ActionContext,valuestack,UserAction,ActionSuport,ModelDriven。userAction里面属性:User对象,userlist集合等
Springmvc是单列。

参数封装来分析:
Struts基于属性进行封装。
Springmvc基于方法封装。

参数绑定

如果使用Model则可以不使用ModelAndView对象,Model对象可以向页面传递数据,View对象则可以使用String返回值替代。不管是Model还是ModelAndView,其本质都是使用Request对象向jsp传递数据

@RequestMapping("/itemEdit")
public String queryItemById(HttpServletRequest request, Model model) {
    // 从request中获取请求参数
    String strId = request.getParameter("id");
    Integer id = Integer.valueOf(strId); 
    // 根据id查询商品数据
    Item item = this.itemService.queryItemById(id); 
    // 把结果传递给页面
    // ModelAndView modelAndView = new ModelAndView();
    // 把商品数据放在模型中
    // modelAndView.addObject("item", item);
    // 设置逻辑视图
    // modelAndView.setViewName("itemEdit"); 
    // 把商品数据放在模型中
    model.addAttribute("item", item); 
    return "itemEdit";
}

简单数据、pojo、包装pojo、数组、List类型

  1. 简单数据类型绑定:

    @RequestMapping("/itemEdit")
    public String queryItemById(int id, ModelMap model) {
  2. pojo类型绑定
    要求:pojo对象中的属性名和表单中input的name属性一致。

    @RequestMapping("/updateItem")
    public String updateItem(Item item)
  3. 包装pojo类型绑定
    要求:包装pojo对象中的属性名和表单中input的name属性一致。
    包装对象定义如下:

    public class QueryVo {
       private Item item;
       set/get。。。
     } 
    
     @RequestMapping("/queryItem")
     public String queryItem(QueryVo queryVo) {
  4. 绑定数组
    包装类型 绑定数组类型,可以使用两种方式,pojo的属性接收,和直接接收

    @RequestMapping("queryItem")
    public String queryItem(QueryVo queryVo, Integer[] ids) {
      System.out.println(queryVo.getIds().length);
      System.out.println(ids.length);
      return "success";
    }
  5. 绑定list
    注意:接收List类型的数据必须是pojo的属性,如果方法的形参为ArrayList类型无法正确接收到数据。
    方法(QueryVo 里面List<Items> itemList

    <input type  name=itemList[${s.index}].name />

自定义参数绑定

  1. 自定义converter

    //Converter<S, T>
    //S:source,需要转换的源的类型
    //T:target,需要转换的目标类型
    public class DateConverter implements Converter<String, Date> { 
      @Override
      public Date convert(String source) {
        try {
          // 把字符串转换为日期类型
          SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
          Date date = simpleDateFormat.parse(source); 
          return date;
        } catch (ParseException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
        // 如果转换异常则返回空
        return null;
      }
    }
  2. 配置converter

    在spring.xml中配置:

    <!-- 配置注解驱动 -->
    <!-- 如果配置此标签,可以不用配置... -->
    <mvc:annotation-driven conversion-service="conversionService" /> 
    <!-- 转换器配置 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
      <property name="converters">
        <set>
          <bean class="cn.springmvc.converter.DateConverter" />
        </set>
      </property>
    </bean>

乱码

在web.xml中加入:

<!-- 解决post乱码问题 -->
<filter>
  <filter-name>encoding</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <!-- 设置编码参是UTF8 -->
  <init-param>
     <param-name>encoding</param-name>
     <param-value>UTF-8</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>encoding</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

对于get请求中文参数出现乱码解决方法有两个:
修改tomcat配置文件添加编码与工程编码一致,如下:

<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

另外一种方法对参数进行重新编码:

String userName new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码

controller方法返回值

  1. ModelAndView
    controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。
  2. void

    1. 使用request转发页面:

      request.getRequestDispatcher("页面路径").forward(request, response);
      request.getRequestDispatcher("/WEB-INF/jsp/success.jsp").forward(request, response); 
    2. 通过response页面重定向:

      response.sendRedirect("url")
      response.sendRedirect("/springmvc-web2/itemEdit.action"); 
    3. 通过response指定响应结果,例如响应json数据:

      response.getWriter().print("{\"abc\":123}"); 
  3. 返回字符串

    1. 指定逻辑视图名,通过视图解析器解析为物理视图地址。

      //指定逻辑视图名,经过视图解析器解析为jsp物理路径:/WEB-INF/jsp/itemList.jsp
      return "itemList"; 
    2. Redirect重定向

      return "redirect:/itemEdit.action?itemId=" + item.getId();
      // 重定向后浏览器地址栏变更为重定向的地址,
      // 重定向相当于执行了新的request和response,所以之前的请求参数都会丢失
      // 如果要指定请求参数,需要在重定向的url后面添加 ?itemId=1 这样的请求参数 
    3. forward转发

      return "forward:/itemEdit.action";
      // 使用转发的方式实现。转发后浏览器地址栏还是原来的请求地址,
      // 转发并没有执行新的request和response,所以之前的请求参数都存在

异常处理器

  1. 自定义异常类

    public class MyException extends Exception {
      // 异常信息
      private String message; 
      public MyException() {
        super();
      } 
      public MyException(String message) {
        super();
        this.message = message;
      } 
      public String getMessage() {
        return message;
      } 
      public void setMessage(String message) {
        this.message = message;
      } 
    }
  2. 自定义异常处理器

    public class CustomHandleException implements HandlerExceptionResolver { 
      @Override
      public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
           Exception exception) {
        // 定义异常信息
        String msg; 
        // 判断异常类型
        if (exception instanceof MyException) {
           // 如果是自定义异常,读取异常信息
           msg = exception.getMessage();
        } else {
           // 如果是运行时异常,则取错误堆栈,从堆栈中获取异常信息
           Writer out = new StringWriter();
           PrintWriter s = new PrintWriter(out);
           exception.printStackTrace(s);
           msg = out.toString(); 
        } 
        // 把错误信息发给相关人员,邮件,短信等方式
        // TODO
        // 返回错误页面,给用户友好页面显示错误信息
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", msg);
        modelAndView.setViewName("error"); 
        return modelAndView;
      }
    }
  3. 配置

    在springmvc.xml中添加:

    <!-- 配置全局异常处理器 -->
    <bean id="customHandleException" class="cn.ssm.exception.CustomHandleException"/>

图片上传

  1. 配置上传解析器

    在springmvc.xml中配置文件上传解析器

    <!-- 文件上传,id必须设置为multipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
      <!-- 设置文件上传大小 -->
      <property name="maxUploadSize" value="5000000" />
    </bean>
  2. jsp

    <!-- 上传图片是需要指定属性 enctype="multipart/form-data" -->
    <!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> -->
    
    <form id="itemForm"action="${pageContext.request.contextPath }/updateitem.action" method="post" enctype="multipart/form-data">
     
    <td>商品图片</td>
    <td>
      <c:if test="${item.pic !=null}">
         <img src="${pageContext.request.contextPath }/pi/${item.pic}" width=100 height=100/>
         <br/>
      </c:if>
      <input type="file"  name="pictureFile"/> 
    </td>
  3. controller

    @RequestMapping("updateItem")
    public String updateItemById(Item item,MultipartFile pictureFile) throws Exception {
      // 图片上传
      // 设置图片名称,不能重复,可以使用uuid
      String picName = UUID.randomUUID().toString(); 
      // 获取文件名
      String oriName = pictureFile.getOriginalFilename();
      // 获取图片后缀
      String extName = oriName.substring(oriName.lastIndexOf(".")); 
      // 开始上传
      pictureFile.transferTo(new File("C:/upload/image/" + picName + extName)); 
      // 设置图片名到商品中
      item.setPic(picName + extName);
      // ---------------------------------------------
      // 更新商品
      this.itemService.updateItemById(item); 
      return "forward:/itemEdit.action";
    }    

ajax方式

  1. 页面ajax
    发送请求,上传图片:图片被关联表单。提交表单:jquery.form.js

    <script type="text/javascript">
    function submitImgSize1Upload(){
      var option={
           type:'POST',
           url:'${pageContext.request.contextPath }/upload/uploadPic.do',
           dataType:'text',
           data:{
              fileName : 'imgSize1File'
           },
           success:function(data){        
              //把json格式的字符串转换成json对象
              var jsonObj = $.parseJSON(data);         
              //返回服务器图片路径,把图片路径设置给img标签
              $("#imgSize1ImgSrc").attr("src",jsonObj.fullPath);
              //数据库保存相对路径
              $("#imgSize1").val(jsonObj.relativePath);
           }      
         };
      $("#itemForm").ajaxSubmit(option);  
    }
    </script>
  2. uploadController
    使用jersy服务器进行跨服务器上传:

    @Controller
    @RequestMapping("/upload")
    public class UploadController {
    
      @RequestMapping("uploadPic")
      public void uploadPic(HttpServletRequest request,String fileName,PrintWriter out){
         //把Request强转成多部件请求对象
         MultipartHttpServletRequest mh = (MultipartHttpServletRequest) request;
         //根据文件名称获取文件对象
         CommonsMultipartFile cm = (CommonsMultipartFile) mh.getFile(fileName);
         //获取文件上传流
         byte[] fbytes = cm.getBytes();        
    
    
     //文件名称在服务器有可能重复?
     String newFileName="";
     SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
     newFileName = sdf.format(new Date());
     
     Random r = new Random();
     
     for(int i =0 ;i<3;i++){
       newFileName=newFileName+r.nextInt(10);
     }     
     //获取文件扩展名
     String originalFilename = cm.getOriginalFilename();
     String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));     
     //创建jesy服务器,进行跨服务器上传
     Client client = Client.create();
     //把文件关联到远程服务器
     WebResource resource = client.resource(Commons.PIC_HOST+"/upload/"+newFileName+suffix);
     //上传
     resource.put(String.class, fbytes);     
     //ajax回调函数需要会写写什么东西?
     //图片需要回显:需要图片完整路径
     //数据库保存图片的相对路径.
     String fullPath = Commons.PIC_HOST+"/upload/"+newFileName+suffix;     
     String relativePath="/upload/"+newFileName+suffix;
     //{"":"","":""}
     String result="{\"fullPath\":\""+fullPath+"\",\"relativePath\":\""+relativePath+"\"}";
     out.print(result);     
      }  
    } 

json数据交互

@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容(json数据)转换为java对象并绑定到Controller方法的参数上。
@ResponseBody注解用于将Controller的方法返回的对象,通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端

restful风格

  1. 使用注解@RequestMapping("item/{id}")声明请求的url{xxx}叫做占位符,请求的URL可以是“item /1”或“item/2”
  2. 使用(@PathVariable() Integer id)获取url上的数据

    /**
     \* 使用RESTful风格开发接口,实现根据id查询商品 
     \* @param id
     \* @return
     */
    @RequestMapping("item/{id}")
    @ResponseBody
    public Item queryItemById(@PathVariable() Integer id) {
      Item item = this.itemService.queryItemById(id);
      return item;
    }

    如果@RequestMapping中表示为"item/{id}",id和形参名称一致,@PathVariable不用指定名称。如果不一致,例如"item/{ItemId}"则需要指定名称@PathVariable("itemId")。

拦截器

总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用

postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用

  1. 定义拦截器

    实现HandlerInterceptor接口,如下:

    public class HandlerInterceptor1 implements HandlerInterceptor {
      // controller执行后且视图返回后调用此方法
      // 这里可得到执行controller时的异常信息
      // 这里可记录操作日志
      @Override
      public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
           throws Exception {
        System.out.println("HandlerInterceptor1....afterCompletion");
      }
     
      // controller执行后但未返回视图前调用此方法
      // 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
      @Override
      public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
           throws Exception {
        System.out.println("HandlerInterceptor1....postHandle");
      }
     
      // Controller执行前调用此方法
      // 返回true表示继续执行,返回false中止执行
      // 这里可以加入登录校验、权限拦截等
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
      // 从request中获取session
      HttpSession session = request.getSession();
       // 从session中获取username
       Object username = session.getAttribute("username");
        // 判断username是否为null
        if (username != null) {
          // 如果不为空则放行
          return true;
        } else {
         // 如果为空则跳转到登录页面
          response.sendRedirect(request.getContextPath() + "/user/toLogin.action");
        } 
       return false;
      }
    }
  2. 配置拦截器

    在springmvc.xml中配置拦截器

    <!-- 配置拦截器 -->
    <mvc:interceptors>
      <mvc:interceptor>
        <!-- 所有的请求都进入拦截器 -->
        <mvc:mapping path="/item/**" />
        <!-- 配置具体的拦截器 -->
        <bean class="cn.ssm.interceptor.HandlerInterceptor1" />
      </mvc:interceptor>
    </mvc:interceptors>

配置

无法处理css、js等静态资源,所以无法正常显示

  1. 解决方案:
    在springmvc.xml中配置

    <!-- 解决静态资源无法被springMVC处理的问题 -->
    <mvc:default-servlet-handler />
  2. 修改web.xml,让所有以action结尾的请求都进入SpringMVC

    <servlet-mapping>
      <servlet-name>boot-crm</servlet-name>
      <!-- 所有的请求都进入springMVC -->
      <url-pattern>*.action</url-pattern>
    </servlet-mapping>

messchx
58 声望5 粉丝

下一篇 »
redis整理