SpringMvc笔记

一、SpringMVC入门
  1. 导包:除了5个基本jar外加入 spring-web-.jar spring-webmvc-.jar

  2. Springmvc核心组件: 核心控制器:DispatcherServlet(web.xml当中配置) 控制器: Controller 处理映射器:HandlerMapping 视图解析器:ViewResolver 拦截器: Interceptors

DispatcherServlet是前端控制器的实现,提供Spring Web MVC的集中访问点,负责职责的分派,且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。

DispatcherServlet主要用作职责调度,主要职责如下:

  • 通过HandlerMapping,将请求映射到处理器;

  • 通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);

  • 通过ViewResolver解析逻辑视图名到具体视图实现;

  • 本地化、国际化解析;

  • 文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;

  • 如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。

  1. web.xml配置(安装了springtools插件alt+/可以直接提示)

    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    默认: servletName-servlet.xml:即hello-servlet.xml,修改方式:

    <init-param>
        <param-name>contextConfigLocation</param-name>
        <!-- 多个文件使用通配符: *-servlet.xml -->
        <param-value>/WEB-INF/hello-servlet.xml(classpath:xxx.xml)</param-value>
    </init-param>
    <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <!-- 直接使用/(不必/*,这样会拦截*.jsp请求,url可以任意.action|.do|.html) -->
            <url-pattern>/</url-pattern>
    </servlet-mapping>

  2. MVC配置文件:

    <!-- 处理器映射:Handler Mapping -->(默认,可以省略不配)
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!-- Controller(通过beanName完成url映射,必须加'/') -->
    <bean name="/start" class="com.cssl.mvc.StartController"/>
    ​
    <!-- 视图解析器:ViewResolver -->(不配可以使用指示符“forward:|redirect:”)
    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    </bean>
    ​
    <!-- 相对UrlBasedViewResolver对jsp和jstl提供了更好的支持,不需要配置viewClass -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    Spring2.5之前,我们都是通过实现Controller接口或其实现类来定义我们的控制器类。

  3. 使用注解:配置少 低侵入

    <mvc:annotation-driven/>:

    自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter两个分发请求bean 视图解析:mav.setViewName("forward:success.jsp"|"success");

  4. 常用注解: 类上:

      @Controller | @RestController(4.0+) | @ControllerAdvice    //将所有属性为UsersVo类型和键名是usersVoList的集合存入request的同时存入session作用域   @SessionAttributes(types=UsersVo.class,value|names={"usersVoList"})两者是or关系   //写在类上相当于namespace   @RequestMapping("/parent")   //或者结合方法上注解@RequestMapping(params="method=方法名")绑定该类下某个方法来执行   @RequestMapping("/user.do") 表单提交action=user.do?method=reg   如:@RequestMapping(params="method=reg")public String reg(String uname){ ... }

    方法上:

      @RequestMapping(value={"/a","/hello"},method=RequestMethod.GET,params="...")   对于相同value的@RequestMapping可以通过method或params区别调用不同方法   对于返回Model或无返回的方法默认视图就是这里的value,如@RequestMapping("/hello")就是hello.jsp   @GetMapping("/...")|@PostMapping("/...")(从Spring4.3开始)

      Spring 3.X系列增加了新注解@ResponseBody,@RequestBody   @ResponseBody将内容或对象作为HTTP响应正文返回,并调用适合HttpMessageConverter转换对象,写入输出流   @ResponseBody绑定返回对象或集合,帮你将其转为Json字符串(默认jackson包,Spring4.0以上版本需要Jackson版本2.x以上的3个包) @ModelAttribute相当前置通知,将返回值注入到model中,能继续传递 @ExceptionHandler异常处理

    参数上:

      @RequestParam(name|value="sid",required=false) int id   @RequestBody将HTTP请求正文转换为Json对象。requestheader Content-Type格式必须application/json或application/xml   @PathVariable 用于restful风格   @CookieValue 取cookie值 @CookieValue(name="JSESSIONID")   Postman添加cookie(先添加域,如:es1.com,然后Add Cookie输入key=value保存就可以了)   @RequestHeader 取请求头信息   @SessionAttribute通常和@SessionAttributes("user")一起使用直接注给方法形参,根据byName注入   @ModelAttribute("user")也可以给模型添加属性(model.addAttribute(user))   如:   在Controller上指定了@SessionAttributes,所以在@ModelAttribute("xxx")注解的参数会直接在  @SessionAttributes中查找名为"xxx"的对象,如果没有找到则调用@ModelAttribute("xxx")注解的方法返回 对象并存入@SessionAttributes

  5. 方法返回值:String(视图名),Model,ModelMap,ModelAndView,Set,List,Object,Map... 除了返回String和ModelAndView,逻辑视图名都会和请求URL绑定 ModelAndView: addObject("uu",user) addObject(new User())==addObject("user",new User()) 使用类名首字母小写作为键 addObject(new ArrayList<User>)==add Object("userList",new ArrayList<User>) addObject("username")==addObject("string","username") 类型名首字母小写作为键 如果返回Map、Model、ModelMap到前台,页面直接取键名 如果将对象或集合当作方法返回值前台页面取值规则也同上!

    重定向传参:RedirectAttributes attr attr.addFlashAttribute("token",token); //(Model model)model.getAttribute("token"); attr.addAttribute("username",username); //相当于地址拼接?username"+username

  6. 访问静态资源:(如jpg,js,css) 如果DispatcherServlet拦截 .action这样的URL,就不存在访问不到静态资源的问题。如果拦截“/”,那么就拦截了所有的请求,即.js,.jpg,.css的访问也就被拦截了当做控制器访问

    解决方法引入资源: a、<mvc:resources location="/static/" mapping="/static/**"/> (注意'/') (静态资源直接映射到对应的文件夹,不被DispatcherServlet处理,3.04新增功能,需要重新设置spring-mvc-3.x.xsd) b、mvc:default-servlet-handler/ (放过所有静态资源) c、原理同上,使用容器默认servlet处理资源,下面是tomcat配置

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css,*.js,*.jpg,*.gif</url-pattern>
    </servlet-mapping>
  7. 解决中文乱码过滤器:(POST)

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>   
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


二、参数注入及Ajax

vo|dto注入、@ResponseBody|@RequestBody|@RestController

  1. 实体类注入:注入多实体类,需要避免实体类同名属性;支持对象导航注入

  2. SpringMvc可以接收数组、List或Map作为参数,但List和Map必须在参数前面加@RequestParam,不能加下标[index],List的泛型类型必须是基本数据类型或String,不能使用自定义类(如:List<Users>),Map注值name为键名

  3. SpringMvc也可以把数组、List或Map作为一个对象的属性接收:

    注意: 如果泛型集合类型是自定义类型:List<Users>,前台必须带[index] 如果泛型集合类型是基本类型或String前台加不加[index]都可以 如果是数组作为实体类属性时前台加不加[index]也都可以

  4. AJAX请求@ResponseBody|@RequestBody(必须有Jackson包)|@RestController 时间转换的处理:(使用Fastjson注解删除Jackson包) a、通过后台的get方法使用SimpleDateFormat解决 b、@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")   @JSONField(format="yyyy-MM-dd",name="")[fastJSON,老版本不支持中文"yyyy年..."] c、@JsonIgnore(true)不序列化该属性   @JSONField(serialize = false)[fastJSON]

  5. Json转换可以由Jackson修改为Fastjson处理:(前端要设置返回类型为json)

<mvc:annotation-driven>
   <mvc:message-converters register-defaults="true">
    <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
        <property name="supportedMediaTypes">
        <list>
            <value>text/plain;charset=UTF-8</value>
            <value>text/html;charset=UTF-8</value>                  
        </list>
        </property>
    </bean>
   </mvc:message-converters>
</mvc:annotation-driven>

注意:

  1. application/x-www-form-urlencoded这种默认请求@RequestBody不支持

  2. @ResponseBody不能转换ModelAndView,仍然使用其中的viewName视图

  3. application/json, application/xml等格式的数据,必须使用@RequestBody来处理

    $.ajax({
        type: "POST",
        url: "json.action",
        contentType: "application/json",  //说明data必须是json字符串
        data: '[{"username":"aaaa"},{"username":"bbbb"}]',
        success: function(msg){
           alert( "Data Saved: " + msg );
        }
    }); 
    //@RequestBody List<UsersVo> list


三、文件上传、Restful及异常处理

文件上传下载|@PathVariable|异常处理@ExceptionHandler|@ControllerAdvice|@ModelAttribute

  1. 文件上传: 表单:enctype="multipart/form-data" method="post" 依赖:commons-fileupload-x.jar、commons-io-x.jar包

@RequestMapping(value="/upload.action") 
public String upload(@RequestParam MultipartFile file) throws IOException {
    //获得真实路径 (可采用接口ServletContextAware注入)
    String path = application.getRealPath("/upload")+File.separator;
    //保证用户没上传不报该错:exists but is a directory
    if(!file.isEmpty()){    
        String type = file.getContentType();        //文件类型        
        String name = file.getOriginalFilename();   //真实文件名               
        String filename = path + name;
        FileUtils.copyInputStreamToFile(file.getInputStream(), new File(filename));
        //或者使用      
        //file.transferTo(new File(path, name)); 
    }       
    return "success";
}
  1. 上传必须配置如下解析器,否则MultipartFile为空:

<!-- 上传解析,如最大上传值及最小上传值,必须配置multipartResolver,名字也不能改 --> 
<bean id="multipartResolver"  
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">     
      <property name="maxUploadSize" value="10000000" /> <!-- 10M --> 
      <property name="maxInMemorySize" value="10240"/>   <!-- 最大临时内存大小 -->
      <property name="defaultEncoding" value="UTF-8"/>     
</bean> 
  1. 多文件上传: a、使用MultipartFile[],参数名和前台file的name相同 b、参数前加@RequestParam在新版本中可以省略(教材上版本低,所以要求必须加)

  2. 下载:

response.setContentType("application/x-msdownload;charset=UTF-8");      
response.setHeader("Content-disposition", "attachment;filename="+fileName);
OutputStream os = response.getOutputStream(); 
//用输入流读取文件再使用os下载到客户端
  1. @RequestMapping不但支持标准的URL,还支持Ant、restful风格。以下URL都是合法的: Ant风格: ?: 匹配一个字符 *: 匹配任意字符 **:匹配多层路径

    • /user/*/createUser 匹配/user/aaa/createUser、/user/bbb/createUser等URL。

    • /user/**/createUser 匹配/user/createUser、/user/aaa/bbb/createUser等URL。

    • /user/createUser?? 匹配/user/createUseraa、/user/createUserbb等URL。

  2. Restful风格: rest:Representational State Transfer(以资源为导向)

    • /user/{userId} 匹配user/123、user/abc等URL。

    • /user/**/{userId} 匹配user/aaa/bbb/123、user/aaa/456等URL。

    • /company/{companyId}/??/{userId}/detail 匹配company/123/us/456/detail等的URL

    • 错误格式 /user/**/{userId}/**/{username}

    优点:因为隐藏了参数与路径的关系,可以提升网站的安全性,静态化页面,降低恶意攻击风险

    //springmvc/path/zhangsan/33
    @RequestMapping(value="/path/{name}/{age}")
    public String path(@PathVariable("name") String sname,@PathVariable("age")...) {
        System.out.println(sname);
        return "hello";
    }
  3. Restful风格也可以注入对象,不用写@PathVariable

    @GetMapping("/company/{username}/{password}")
    public String rest(UsersVo uvo) {       
        System.out.println("rest:"+uvo.getUsername()+":"+uvo.getPassword());        
        return "success";
    }
  4. SpringMVC提供的异常处理主要有

    • 实现HandlerExceptionResolver接口,自定义异常处理 SpringMVC本身也已经对其有一个默认的实现——DefaultExceptionResolver,该解析器只是对其中的一些比较典型的异常进行了拦截处理。

      <bean id="exceptionResolver" class="com.cssl.handler.MyExceptionHandler"/>
    • 使用@ExceptionHandler进行处理(局部异常) 使用@ExceptionHandler进行异常处理的方法必须与出错的方法在同一个Controller里面 一定要注明处理哪种异常类型 @ExceptionHandler(Exception.class) public String error(Exception e){}

    • 针对所有Controller异常处理(全局异常但不包括类型转换异常) springmvc.xml配置

      <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
         <property name="exceptionMappings">
          <props>
              <prop key="java.lang.Exception">error</prop>
          </props>
         </property>
      </bean>
    • @ControllerAdvice+@ExceptionHandler 全局处理Controller层异常 优点:将Controller层的异常和数据校验的异常进行统一处理,减少编码量,提升扩展性和可维护性 缺点:只能处理Controller层未捕获(往外抛)的异常,对于Interceptor(拦截器)层的异常,Spring框架层的异常,就无能为力了

    @ControllerAdvice 
    public class GlobalExceptionHandler { 
    ​
       @ExceptionHandler(Exception.class) 
       @ResponseBody 
       public String handleException(){ ...; } 
    ​
       /**
        * 前置通知
        * @return
        */
       @ModelAttribute
       public Users getModel() {    
        Users u = new Users();  
        u.setUsername("匿名用户");
        return u;
       }
        
        
      //姓名  密码  角色 【正是用户 游客】
        @ModelAttribute //先帮你效验数据 ,提前去补缺 
        public void userLogin2(Users user/* ,Model md */) {
            System.out.println("进来了:"+user);
            //md.addAttribute("users", user);
        }
        
        
        @RequestMapping("/userLogin2.action")
        public String login2(@RequestParam(required = false) Users user,Model md) {
            Users u = (Users) md.getAttribute("users");
            System.out.println("u:"+u);
            System.out.println("UsersController-login2-登录2方法--:"+u);
            return "success";
        }
    }

    https://www.jianshu.com/p/0ec4e7afb7ed

    @ControllerAdvice配合@ExceptionHandler最有用,其它两个不常用

    @ControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(IllegalArgumentException.class)
        public ModelAndView handleException(IllegalArgumentException e){
            ModelAndView modelAndView = new ModelAndView("error");
            modelAndView.addObject("errorMessage", "参数不符合规范!");
            return modelAndView;
        }
    }
    ​

    @ControllerAdvice 配合 @ModelAttribute 预设全局数据

    我们先来看看 ModelAttribute注解类的源码

    @ControllerAdvice
    public class MyGlobalHandler {
        @ModelAttribute
        public void presetParam(Model model){
            model.addAttribute("globalAttr","this is a global attribute");
        }
    }
    ​
    @ControllerAdvice
    public class MyGlobalHandler {
    ​
        @ModelAttribute()
        public Map<String, String> presetParam(){
            Map<String, String> map = new HashMap<String, String>();
            map.put("key1", "value1");
            map.put("key2", "value2");
            map.put("key3", "value3");
            return map;
        }
    ​
    }
    ​
    @RestController
    public class AdviceController {
    ​
        @GetMapping("methodOne")
        public String methodOne(Model model){ 
            Map<String, Object> modelMap = model.asMap();
            return (String)modelMap.get("globalAttr");
        }
    ​
      
        @GetMapping("methodTwo")
        public String methodTwo(@ModelAttribute("globalAttr") String globalAttr){
            return globalAttr;
        }
    ​
    ​
        @GetMapping("methodThree")
        public String methodThree(ModelMap modelMap) {
            return (String) modelMap.get("globalAttr");
        }
        
    }
    ​
    @ControllerAdvice 配合 @InitBinder 实现对请求参数的预处理
    @ControllerAdvice
    public class MyGlobalHandler {
    ​
        @InitBinder
        public void processParam(WebDataBinder dataBinder){
    ​
            /*
             * 创建一个字符串微调编辑器
             * 参数{boolean emptyAsNull}: 是否把空字符串("")视为 null
             */
            StringTrimmerEditor trimmerEditor = new StringTrimmerEditor(true);
    ​
            /*
             * 注册自定义编辑器
             * 接受两个参数{Class<?> requiredType, PropertyEditor propertyEditor}
             * requiredType:所需处理的类型
             * propertyEditor:属性编辑器,StringTrimmerEditor就是 propertyEditor的一个子类
             */
            dataBinder.registerCustomEditor(String.class, trimmerEditor);
            
            //同上,这里就不再一步一步讲解了
            binder.registerCustomEditor(Date.class,
                    new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
        }
    }
    ​
    ​
    @RestController
    public class BinderTestController {
    ​
        @GetMapping("processParam")
        public Map<String, Object> test(String str, Date date) throws Exception {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("str", str);
            map.put("data", date);
            return  map;
        }
    }
    ​
    class Person {
    ​
        private String name;
        private Integer age;
        // omitted getters and setters.
    }
    ​
    class Book {
    ​
        private String name;
        private Double price;
        // omitted getters and setters.
    }
    ​
    @RestController
    public class BinderTestController {
    ​
        @PostMapping("bindParam")
        public void test(Person person, Book book) throws Exception {
            System.out.println(person);
            System.out.println(book);
        }
    }
    ​

    我们会发现 Person类和 Book 类都有 name属性,那么这个时候就会出先问题,它可没有那么只能区分哪个name是哪个类的。因此 @InitBinder就派上用场了:

    @ControllerAdvice
    public class MyGlobalHandler {
    ​
        /*
         * @InitBinder("person") 对应找到@RequstMapping标识的方法参数中
         * 找参数名为person的参数。
         * 在进行参数绑定的时候,以‘p.’开头的都绑定到名为person的参数中。
         */
        @InitBinder("person")
        public void BindPerson(WebDataBinder dataBinder){
            dataBinder.setFieldDefaultPrefix("p.");
        }
    ​
        @InitBinder("book")
        public void BindBook(WebDataBinder dataBinder){
            dataBinder.setFieldDefaultPrefix("b.");
        }
    }
    ​
    因此,传入的同名信息就能对应绑定到相应的实体类中:
    ​
    p.name -> Person.name b.name -> Book.name
    ​
    还有一点注意的是如果 @InitBinder("value") 中的 value 值和 Controller 中 @RequestMapping() 标识的方法的参数名不匹配,则就会产生绑定失败的后果,如:
    ​
    @InitBinder(“p”)、@InitBinder(“b”)
    ​
    public void test(Person person, Book book)
    ​
    上述情况就会出现绑定失败,有两种解决办法
    ​
    第一中:统一名称,要么全叫p,要么全叫person,只要相同就行。
    ​
    第二种:方法参数加 @ModelAttribute,有点类似@RequestParam
    ​
    @InitBinder(“p”)、@InitBinder(“b”)
    ​
    public void test(@ModelAttribute(“p”) Person person, @ModelAttribute(“b”) Book book)
    ​

    @ControllerAdvice也可配合@InitBinder和@ModelAttribute方法,适用所有使用@RequestMapping方法

    @ControllerAdvice在Spring4之前协助所有控制器。Spring4+已经改变:支持配置控制器的子集 如:@ControllerAdvice(basePackages="com.cssl.controller")对其他包控制器不起作用


四、拦截器、类型转换、国际化、验证

https://www.cnblogs.com/sfnz/p/16478087.html

  1. 拦截器:实现HandlerInterceptor接口或继承HandlerInterceptorAdapter(责任链模式)

    <!-- intercepter -->
    <mvc:interceptors>
       <!-- 配置多个形成拦截器链 -->
       <mvc:interceptor>
        <!-- /**将拦截所有包括静态资源但不包括jsp,如果jsp包含静态js也会经过拦截器 -->
        <!-- /*只拦截一级目录下所有Controller,如:/he.action,不拦截二级目录 -->    
        <mvc:mapping path="/**"/>|<mvc:mapping path="/*"/>
        <!-- 如果拦截了所有,必须设置放过静态资源 -->
        <mvc:exclude-mapping path="/static/**"/>
        <bean class="com.cssl.interceptor.MyInterceptor"/>
       </mvc:interceptor>
    </mvc:interceptors>

    拦截器参数handler中包含请求类及方法,可以精确控制调用方法权限 handler.toString().indexOf("方法名")!=-1

  2. 类型转换: a、基本类型的数据类型转换自动完成 日期类型转换(springmvc只提供yyyy/MM/dd这样的格式转换)

    b、@InitBinder //注解方式转换,只能转换一种格式,项目中日期类型较多首选

    public void initBind(DataBinder binder){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //true表示该日期字段可以为空
        binder.registerCustomEditor(Date.class, new CustomDateEditor(sdf,false));   
    }

    c、直接在vo的属性上(get|set也可以)注解@DateTimeFormat(pattern="yyyy-MM-dd")

    BindingResult:该类封装转换失败的信息,必须紧跟在command类型参数后面,日期必须是command属性 result.hasErrors()判断是否转换出错

  3. 自定义类型转换: Spring3引入了一个Converter接口,它支持从一个Object转为另一个Object。除了Converter接口之外,实现 ConverterFactory接口和GenericConverter接口也可以实现我们自己的类型转换逻辑。 a、定义转换类实现Converter<S,T>接口重写convert实现类型转换功能 b、添加注解@Component注册到bean到Spring容器 c、配置

    <bean id="conversionService"    class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
            <ref bean="dateConverter"/>
            </set>
        </property>
    </bean>
    或者手动注入日期格式类型:
        <set>
           <bean class="com.cssl.converter.DateConverter">
            <constructor-arg type="java.lang.String" value="yyyy-MM-dd"/>
           </bean>
        </set>

    d、修改<mvc:annotation-driven conversion-service="conversionService"/>

  1. 国际化:IE11设置语言问题(不显示中文可以先删除英文语言选项) a、先配置属性文件message_en.properties | message_zh_CN.properties b、在JSP文件中使用fmt标记就可以实现语言国际化   如:  

    <fmt:setBundle basename="message"/>
    <fmt:message key="info.login.title" />  

    属性文件显示中文插件: Eclipse Marketplace->find properties->选择Properties Editor

  2. Spring3开始支持JSR-303验证框架: 验证使用的包hibernate-validator-5.0.1.Final-dist 最少需要4个jar: hibernate-validator-5.0.1.Final.jar required:classmate-0.8.0.jar、jboss-logging-3.1.1.GA.jar、validation-api-1.1.0.Final.jar

    注解: 1、在vo参数前添加@Valid|@Validated,后面紧跟BindingResult参数不能间隔其他参数 2、在实体类要验证的属性getXxx上添加各种验证注解 @NotNull(空对象)、 @NotEmpty(字符串)、@NotBlank(去首尾空格)、 @Size(min=4,max=6)、@Email 3、使用<sf:errors path="vo.fieldName"/>显示错误(vo对应实体类首字母小写UsersVo-usersVo) 4、国际化显示可以不写message,有默认出错信息提示,如果想自定义则修改键名(key)为: Size.usersVo.username ,其含义为(Size代表@Size,usersVo代表vo,username代表fileName), 使用sf提示消息,也必须配置bean:ResourceBundleMessageSource 5、<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %> <sf:errors path="usersVo.username"/> 注意:使用springmvc标签必须配置监听器,除非是通过控制器访问页面

    <listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>   
    </listener>


五、SSM整合
  1. 整合 a、导入之前整合的Spring+MyBatis b、web.xml配置监听器启动Spring的IoC容器(或者直接在springmvc.xml引入spring.xml)

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    ​
    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:beans.xml</param-value>  //spring配置beans.xml
    </context-param>

    注意:MyBatis没有Spring事务管理的问题:(直接在springmvc.xml引入spring.xml不会有事务问题)

    第一种情况: 两个容器产生两套控制器和业务类,请求调用的是springmvc容器的而事务是控制在spring容器上!

    解决:MVC的springmvc.xml配置文件中只扫描包含controller的注解,Spring的beans.xml文件中扫描包时,排除controller的注解,如下所示:

    SpringMVC的xml配置:

    <context:component-scan base-package="com.cssl.controller"/> 

    Spring的xml配置:(不扫描带有@Controller注解的类,因为这些类在springmvc.xml中扫描)

    <context:component-scan base-package="com.cssl">           
        <context:exclude-filter type="annotation"                                             expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    只用一个配置文件:(相当直接在springmvc.xml引入spring.xml)

    第二种情况:MySQL数据没用InnoDB引擎,修改数据库引擎即可

  2. Web环境中可以使用:@Scope("request|session")

  3. Web(过滤器|监听器)获取当前的SpringIoC容器(必须使用监听器启动IoC容器:因为监听器先于Servlet启动) 方法一:(通过ServletContext加载spring容器,SpringBoot适用) ApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(application);

    方法二:(获取当前的spring容器,任何java类中适用,SpringBoot不适用,SpringBoot可以直接注入ioc容器中的对象) WebApplicationContext act=ContextLoader.getCurrentWebApplicationContext();

  4. 防止Spring内存溢出监听器

    <listener>
        <listener-class>
            org.springframework.web.util.IntrospectorCleanupListener
        </listener-class>
    </listener>

    注意:Web组件加载顺序:监听器 -》 过滤器 -》 Servlet


扩展知识点:

自定义视图:

  1. 写一个类实现View接口,实现其两方法

public String getContentType() {        
    return "text/html;charset=utf-8";
}

//渲染视图,输出到客户端

public void render(Map<String, ?> model, HttpServletRequest request,
        HttpServletResponse response) throws Exception {
    System.out.println("render:"+model.get("usersVo"));
    response.getWriter().print("<h1>MyView:"+new Date()+"</h1>");
}
  1. 使用@Component将该类注册到spring ioc容器

  2. 配置ViewResolver(根据id查找对应的视图解析类)

    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
        <!-- 数字越小代表优先级越高 -->
        <property name="order" value="100"/>    
    </bean>

    如:@Component("myView")类映射方法不能通过超链接的方式直接访问

    //这里的myview映射前台链接,return的"myView"对应@Component("myView")
    @RequestMapping("/myview")
    public String myview(){
        return "myView";
    }
  3. 如果经常用到下载可以封装下载view:

response.setContentType("application/x-excle;charset=UTF-8");       
response.setHeader("Content-disposition", "attachment;filename="+fileName);
OutputStream os = response.getOutputStream(); 
//读
InputStream in = new FileInputStream(path);
byte[] b = new byte[4096];
int len = in.read(b);
//写
while(len!=-1) {
    os.write(b,0,len);
    len = in.read(b);
}
os.flush();
os.close();
in.close();
5.自定义视图
package com.cssl.view;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.View;
import com.cssl.pojo.Student;
@Component
public class MyView implements View {
    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        Student object = (Student) model.get("stu");
        System.out.println("render:"+object);
        response.getWriter().print("<h1>"+object.getStudentName()+"MyView:"+new Date()+"</h1>");
        
    }
​
}
​

下载视图:

package com.cssl.view;
​
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
​
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
​
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.document.AbstractXlsView;
​
import com.cssl.pojo.Student;
@Component
public class ExcelView extends AbstractXlsView {
​
    @Override
    protected void buildExcelDocument(
            Map<String, Object> model,
            Workbook workbook,
            HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        //从model取出数据
        List<Student> stus = (List<Student>) model.get("stus");
        //定义下载后excel表格名称
        String fileName="student.xlsx";
        //设置下载头
        response.setContentType("application/ms-excel;charset=UTF-8");
        response.setHeader("Content-Disposition", "inline; filename=" + fileName);
        
        //创建一个Sheet
        Sheet sheet = workbook.createSheet("学生信息");
        
        //创建行
        Row firstRow = sheet.createRow(0);
        firstRow.createCell(0).setCellValue("序号");
        firstRow.createCell(1).setCellValue("主键");
        firstRow.createCell(2).setCellValue("姓名");
        firstRow.createCell(3).setCellValue("生日");
        firstRow.createCell(4).setCellValue("备份");
        
        if(stus==null) {
            return;
        }else {
            for (int i = 0; i < stus.size(); i++) {
                Student stu=stus.get(i);
                Row tempRow = sheet.createRow(i+1);
                tempRow.createCell(0).setCellValue(i+1);
                tempRow.createCell(1).setCellValue(stu.getSid());
                tempRow.createCell(2).setCellValue(stu.getStudentName());
                tempRow.createCell(3).setCellValue(stu.getBorndate());
                tempRow.createCell(4).setCellValue("菜鸡");
            }
        }
        
        ServletOutputStream out=response.getOutputStream();
        workbook.write(out);//输出
        System.out.println("下载ok");
        out.flush();
        out.close();
        
    }
​
}
​
@RequestMapping("/test")
	public String myViewTest(Model model) {
		
		Student student =new Student();
		student.setSid(1111);
		student.setStudentName("老刘");
		student.setBorndate(new Date());
		model.addAttribute("stu", student);
		
		return "myView";
	}
	
	@RequestMapping("/export")
	public ModelAndView export(ModelAndView mv,Model model) {
		List<Student> stus = studentService.findAllStudent();
		model.addAttribute("stus", stus);
		
		mv.setView(new ExcelView());
		
		return mv;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值