zoukankan      html  css  js  c++  java
  • Spring MVC

    DOC:17.Web MVC framework

    一、
    1、导包:除了5个基本jar外
    spring-web-*.jar
    spring-webmvc-*.jar
    spring4.0以上还需导入aop包
    spring4开始,以Servlet3进行开发

    2、springmvc核心组件:
    核心控制器:DispatcherServlet
    控制器: Controller(UrlFilenameViewController | SimpleFormController | MultiActionController ...)
    请求分发器:Handler Mapping
    视图解析器:ViewResolver & View
    拦截器: Interceptors


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

    DispatcherServlet主要用作职责调度,用于控制流程,主要职责如下:
    1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
    2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
    3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
    4、通过ViewResolver解析逻辑视图名到具体视图实现;
    5、本地化解析;
    6、渲染具体的视图等;
    7、如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。


    3、web.xml配置
    <servlet-name>hello</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    默认:
    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>example</servlet-name>
    <!-- 直接使用/(不必/*,这样会拦截*.jsp请求) -->
    <url-pattern>/</url-pattern>
    </servlet-mapping>

    4、MVC配置文件:
    schema:17.15.1 Enabling the MVC Java Config or the MVC XML Namespace

    <!-- Handler Mapping -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

    <!-- Controller(通过beanName完成url映射,必须加'/') -->
    <bean name="/start" class="com.cssl.mvc.StartController"></bean>

    视图解析器ViewResolver:
    <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接口或其实现类来定义我们的控制器类。


    5、使用注解:配置少 低侵入(无需配置HandlerMapping、ViewResolver)
    <context:component-scan base-package="com.cssl.mvc"/>
    <mvc:annotation-driven/>:
    自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter两个bean,是springMVC为Controller分发请求的Bean
    视图解析:mav.setViewName("forward:success.jsp");

    <!--
    将指定路径的请求直接转到对应的view上,而不需要特定的controller来处理请求 .
    注意:此处的映射路径是/hello,请求时http://localhost:8080/springmvc/hello
    不能写hello.action,而不使用此种方式的映射可以加的,因为web.xml配置的是‘/’
    -->
    <mvc:view-controller path="/hello" view-name="hello" />


    常用注解:
    类上:@Controller
    //将所有属性为UsersVo类型和键名是usersVoList的集合存入request的同时存入session作用域,另外注意集合方式必须返回ModelAndView(集合也可以使用ArrayList.class)
    @SessionAttributes(types=UsersVo.class,value={"usersVoList"})两者是and关系,需要同时满足。
    //写在类上相当于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={"/","/hello"},method=RequestMethod.GET,params="...")
    对于相同value的@RequestMapping可以通过method或params区别调用不同方法
    对于无返回值或返回Model的方法默认视图就是这里的value,如@RequestMapping("/hello")就是hello.jsp

    Spring 3.X系列增加了新注解@ResponseBody,@RequestBody
    @RequestBody将HTTP请求正文转换为Json对象。request header Content-Type格式必须application/json或application/xml
    @ResponseBody将内容或对象作为HTTP响应正文返回,并调用适合HttpMessageConverter转换对象,写入输出流
    @ResponseBody注解,表示该方法将会跳过视图处理部分将返回结果直接写入HTTP response body中。
    @ResponseBody绑定返回对象或集合,帮你将其转为Json(相当于struts的json插件功能)字符串(默认jackson的2个包struts2中找1.9x,Spring4.0以上版本需要Jackson新版本2.x以上的3个包)
    @ModelAttribute

    参数:@RequestParam(name|value="id",required=false) int id
    @PathVariable 用于restful风格
    @CookieValue(name|value="id",required=false) 取cookie值 @CookieValue(name="JSESSIONID")
    @RequestHeader(name|value="id",required=false) 取请求头信息
    @ModelAttribute("user")通常和@SessionAttributes("user")一起使用直接注给方法形参,也可以给模型添加属性(model.addAttribute(user))
    如:
    在Controller上指定了@SessionAttributes,所以在@ModelAttribute("xxx")注解的参数会直接在@SessionAttributes中查找名为"xxx"的对象,如果没有找到则调用@ModelAttribute("xxx")注解的方法返回对象并存入@SessionAttributes

    方法返回值可以是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>)==addObject("userList",new ArrayList<User>) 集合
    addObject("username")==addObject("string","username") 类型名做键
    如果返回Map、Model、ModelMap到前台,页面直接取键名
    如果将对象或集合当作方法返回值前台页面取值规则也同上!

    ModelMap: addAttribute(user)|put("user", user);
    Model: addAttribute(user)

    如何访问到静态的文件,如jpg,js,css:如果你的DispatcherServlet拦截 *.do这样的URL,就不存在访问不到静态资源的问题。如果你的DispatcherServlet拦截“/”,拦截了所有的请求,同时对*.js,*.jpg的访问也就被拦截了
    解决方法引入资源:
    a、<mvc:resources location="/resource/" mapping="/resource/**"/> (注意'/')
    (静态资源直接映射到对应的文件夹,不被DispatcherServlet处理,3.04新增功能,需要重新设置spring-mvc-3.x.xsd)
    b、<mvc:default-servlet-handler/> (兼容不同容器默认servlet处理资源)
    c、原理同上,使用容器默认servlet处理资源,下面是tomcat配置
    <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
    </servlet-mapping>

    解决中文乱码过滤器:
    <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>


    *****************************************************************************************

    二、vo注入、@ResponseBody|Restful|@PathVariable风格

    1、实体类注入:可以注入多个实体类,需要避免实体类同名属性(同名属性默认当数组处理)

    2、SpringMvc可以直接接收数组、List、Set或Map作为参数,但集合和Map必须在参数前面加@RequestParam:[@RequestParam Map<String, Object> param],而且不能加下标[index],List的泛型类型必须是基本数据类型或String,不能使用自定义类,如:List<Users>

    3、SpringMvc也可以把数组、List、Set或Map作为一个对象的属性接收:
    注意:
    如果泛型集合类型是自定义类型只能采用这种方式:List<Users>,前台必须带[index]
    (不能加@RequestParam)
    如果泛型集合类型是基本类型或String前台加不加[index]都可以

    数组作为实体类属性时前台加不加[index]也都可以
    Set集合不能使用下标,可以像数组一样不用下标的方式注入

    4、重定向:return "redirect:...";

    5、转发到另一action:可以带method也可以省略
    forward:ff.action[?method=forwardAction]

    只要加了redirect:或forward:则后面都变成url不再是逻辑视图名!


    6、AJAX请求@ResponseBody|@RequestBody(Jackson)
    时间转换的处理:
    a、通过后台的get方法中使用SimpleDateFormat解决
    b、@JsonFormat(pattern="yyyy-MM-dd")
    c、@JsonIgnore(true)不序列化该属性

    json转换也可以由Jackson修改为fastjson处理:
    <mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
    <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
    <property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>
    </bean>
    </mvc:message-converters>
    </mvc:annotation-driven>


    7、@RequestMapping不但支持标准的URL,还支持Ant、restful风格。以下URL都是合法的:(Spring 3.0新增功能)
    Ant风格:
    ?: 匹配一个字符
    *: 匹配任意字符
    **:匹配多层路径
    1./user/*/createUser
    匹配/user/aaa/createUser、/user/bbb/createUser等URL。
    2./user/**/createUser
    匹配/user/createUser、/user/aaa/bbb/createUser等URL。
    3./user/createUser??
    匹配/user/createUseraa、/user/createUserbb等URL。

    Restful风格:
    rest:Representational State Transfer(以资源为导向)
    1./user/{userId}
    匹配user/123、user/abc等URL。
    2./user/**/{userId}
    匹配user/aaa/bbb/123、user/aaa/456等URL。
    3.company/{companyId}/??/{userId}/detail
    匹配company/123/us/456/detail等的URL
    4.错误格式
    /user/**/{userId}/**/{username}

    优点:因为隐藏了参数与路径的关系,可以提升网站的安全性,静态化页面,降低恶意攻击风险。
    //springmvc/path/zhangsan/33
    @RequestMapping(value="/path/{name}/{age}")
    public String path(@PathVariable("name") String name,@PathVariable("age")...) {
    System.out.println(name);
    return "hello";
    }
    @PathVariable:映射URL中的占位符到目标方法的参数中


    *****************************************************************************************


    三、文件上传下载、拦截器、类型转换、国际化、验证、整合事务

    1、文件上传:enctype="multipart/form-data" method="post"
    依赖commons-fileupload-x.jar、commons-io-x.jar包
    @RequestMapping(value="/upload2") (url不要和文件夹同名,否则异常,可以加.action)
    public String upload(
    @RequestParam MultipartFile file,
    MultipartHttpServletRequest request
    ) throws IOException {

    //保证用户没上传不报该错:exists but is a directory
    if(!file.isEmpty()){
    System.out.println(file.getContentType()+":"+file.getName());
    //真实文件名
    System.out.println(file.getOriginalFilename());
    //获得真实路径 (也可采用接口ServletContextAware注入)
    String path = application.getRealPath("/upload")+File.separator;
    String name = path + file.getOriginalFilename();
    FileUtils.copyInputStreamToFile(file.getInputStream(), new File(name));
    //或者使用
    //file.transferTo(new File(path, name));

    }
    return "redirect:hello";
    }

    上传必须配置如下解析器,否则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="uploadTempDir" value="/temp/"/> <!-- 上传后的临时目录名 -->
    </bean>

    多文件上传:
    A、使用MultipartFile[],参数名和前台file的name相同
    B、参数前加@RequestParam在新版本中可以省略

    下载:
    response.setContentType("application/x-msdownload;charset=UTF-8");
    response.setHeader("Content-disposition", "attachment;filename="+fileName);
    OutputStream os = response.getOutputStream(); 使用该流向客户端输出!

    2、拦截器:实现HandlerInterceptor接口或继承HandlerInterceptorAdapter
    <!-- intercepter -->
    <mvc:interceptors>
    <!-- 配置多个形成拦截器链 -->
    <mvc:interceptor>
    <!-- /**将拦截所有包括静态资源但不包括jsp,如果jsp包含静态js也会经过拦截器,但不会阻止js的下载 -->
    <!-- /*只拦截一级目录下所有Controller,如:/he.action,但不拦截二级目录及静态资源 -->
    <mvc:mapping path="/**"/>|<mvc:mapping path="/*"/>
    <!-- 如果拦截了所有最好也设置放过静态资源 -->
    <mvc:exclude-mapping path="/resource/**"/>
    <bean class="com.cssl.interceptor.MyInterceptor"></bean>
    </mvc:interceptor>
    </mvc:interceptors>


    3、类型转换:
    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()判断是否转换出错


    4、自定义类型转换:
    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="xxxConverter"/>
    </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"/>


    5、国际化:IE11设置语言问题,不显示中文可以先删除英文语言选项
    <!-- 资源文件绑定器 -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename" value="message"/>
    <property name="useCodeAsDefaultMessage" value="true"/>
    </bean>
    然后配置JSP渲染器为JSTL支持的,那么在你的JSP文件中使用fmt标记就可以实现客户浏览器语言国际化
      如:
    <fmt:setBundle basename="message"/>
      <fmt:message key="info.login.title" />
      其中的info.login.title和你的资源文件对应.

    官方给出另外一种方式是使用spring自带的标签显示国际化信息,
    如:<spring:message code="main.title" />


    6、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参数前添加@Validated,后面紧跟BindingResult参数不能间隔其他参数
    2、在实体类要验证的属性getXxx上添加各种验证注解
    @NotNull(数字)、 @NotEmpty(字符串)、 @Size(min=4,max=6)、@Email
    3、使用<sf:errors path="vo.fieldName"/>显示错误(vo对应实体类首字母小写UsersVo-usersVo)
    4、国际化显示可以不写message,有默认出错信息提示,如果想自定义则修改键名(key)为:
    Size.usersVo.name ,其含义为(Size代表@Size,usersVo代表vo,name代表fileName)

    7、整合问题
    MyBatis没有Spring事务管理的问题:
    第一种情况:
    注解方式:
    Spring MVC 和 Spring 整合的时候,SpringMVC的springmvc.xml文件中配置扫描包,只包含controller的注解,Spring的applicationContext.xml文件中配置扫描包时,不要包含controller的注解,如下所示:
    SpringMVC的xml配置:
    <context:component-scan base-package="com.cssl.controller"/>

    因为springmvc.xml与applicationContext.xml都会加载,springmvc会将所有带@Service注解的类扫描并注入到Controller,加载applicationContext.xml的时候,spring同样会再产生service层和控制层对象,使得cglib将不对Service进行代理,直接导致的结果就是在applicationContext中的事务配置不起作用,发生异常时,无法对数据进行回滚。(Hibernate直接异常,找不到事务!)
    在Spring的xml配置如下:(如果不设置过滤,还会产生一个Controller,只不过不会被springmvc调用)
    <context:component-scan base-package="com.cssl">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    扫描包路径,不扫描带有@Controller注解的类。因为这些类在springmvc.xml中将被扫描。

    根本原因:两个容器产生两套控制器和业务类,请求调用的是springmvc容器的而事务是控制在spring容器上(先初始化的是spring容器:监听器先于servlet执行)


    只用一个配置文件:
    合成一个配置文件也存在被加载两次生成两套类的问题,只能设置读取springmvc配置文件,不配监听
    因为springmvc的核心servlet必须要能扫描到controller,否则无法访问控制器

    Love馨蕊
  • 相关阅读:
    使用javamail发信过程中的一些问题及解决方法
    互联网标准
    发送邮件报错javax.activation.UnsupportedDataTypeException: no object DCH for MIME type text/plain; charset=UTF-8
    在用split分割处理csv数据时,使用不包含在双引号中的逗号进行分割
    java 网络代理官方资料
    ORA-28000错误的原因及解决办法
    日文软件下载站点
    Azure 入门
    ElasticSearch 5学习(10)——结构化查询(包括新特性)
    ElasticSearch 5学习(9)——映射和分析(string类型废弃)
  • 原文地址:https://www.cnblogs.com/yuan211/p/8334760.html
Copyright © 2011-2022 走看看