SpringMVC

Updated on with 0 views and 0 comments

配置

webmvc.xml

<!--  配置DispatcherServlet  -->
    <servlet>
        <servlet-name>SpringDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置DispatcherServlet的一个初始化参数:配置SpringMVC配置文件的名称和路径 -->
	<!--
            实际上也可以不通过contextConfigLocation来配置SpringMVC的配置文件,而使用默认的
            默认的配置文件为:/WEB-INF/<servlet-name>-servlet.xml
        -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

springmvc.xml

<!-- 处理器映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!-- 注解驱动
        这一个相当于上面两个
-->
<mvc:annotation-driven/>

    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="top.wu.controller"></context:component-scan>

    <!-- 配置视图解析器 - 把handler返回的值解析为实际的物理视图-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

@RequestMapping 映射请求

在控制器的类定义及方法定义处都可标注 @RequestMapping

  • 类定义处:提供初步的请求映射信息。相对于 WEB 应用的根目录
  • 方法处:提供进一步的细分映射信息。相对于类定义处的 URL。若类定义处未标注 @RequestMapping,则方法处标记的 URL 相对于WEB 应用的根目录

属性

@RequestMapping 的 value、method、params 及 heads

分别表示请求 URL、请求方法、请求参数及请求头的映射条

件,他们之间是与的关系,联合使用多个条件可让请求映射

更加精确化。

params 和 headers支持简单的表达式:

  • param1: 表示请求必须包含名为 param1 的请求参数
  • !param1: 表示请求不能包含名为 param1 的请求参数
  • param1 != value1: 表示请求包含名为 param1 的请求参数,但其值

不能为 value1

  • {“param1=value1”, “param2”}: 请求必须包含名为 param1 和param2

的两个请求参数,且 param1 参数的值必须为 value1

@PathVariable 映射 URL 绑定的占位符

通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过 @PathVariable("xxx") 绑定到操作方法的入参中。

使用 @RequestParam 绑定请求参数值

在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法

  • value:参数名
  • required:是否必须。默认为 true, 表示请求参数中必须包含对应

的参数,若不存在,将抛出异常

@CookieValue 可让处理方法入参绑定某个 Cookie 值

    @RequestMapping("/hello")
    public void testCookieValue(@CookieValue(value = "JSESSIONID") String JSESSIONID) {
        System.out.println(JSESSIONID);
    }

使用 POJO 对象绑定请求参数值

Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。

如:dept.deptId、dept.address.tel 等

使用Servlet API 作为入参

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
  • java.security.Principal
  • Locale
  • InputStream
  • OutputStream
  • Reader
  • Writer

处理模型数据

ModelAndView

控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。 SpringMVC会把ModelAndView的model中的数据放到request域对象中

• 添加模型数据:

– MoelAndView addObject(String attributeName, Object

attributeValue)

– ModelAndView addAllObject(Map<String, ?> modelMap)

• 设置视图:

– void setView(View view)

– void setViewName(String viewName)

Map

@RequestMapping("/testmap")
    //实际上也可以是Model、ModelMap类型
    public String testMap(Map<String,Object> map) {
        map.put("test","test");
        return "success";
    }

@SessionAttributes

若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个 @SessionAttributes, Spring MVC 将在模型中对应的属性暂存到 HttpSession 中。

• @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中

– @SessionAttributes(types=User.class) 会将隐含模型中所有类型 为 User.class 的属性添加到会话中。

– @SessionAttributes(value={“user1”, “user2”})

– @SessionAttributes(types={User.class, Dept.class})

– @SessionAttributes(value={“user1”, “user2”}, types={Dept.class})

PS:这个注解只能放在类的上面

@ModelAttribute

• 在方法定义上使用 @ModelAttribute 注解:Spring MVC在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribute 的方法。

• 在方法的入参前使用 @ModelAttribute 注解:

– 可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参

– 将方法入参对象添加到模型中

执行步骤

1.执行@ModelAttribute注解修饰的方法:从数据库中取出对象,把对象放入到Map中,键为user
2.SpringMVC从Map中取出User对象,并把请求参数赋给User对象对应的属性
3.SpringMVC把上述对象传入目标方法的参数

注意:在@ModelAttribute修饰的方法中,放入到Map时的键需要和目标方法的入参类型的第一个字母小写的字符串一致

调用流程

1.调用@ModelAttribute注解修饰的方法,实际上把@ModelAttribute方法中Map中的数据放在了implicitModel中。
2.解析请求处理器的目标参数,实际上该属性来自于WebDataBinder对象的target属性。
(1)创建WebDataBinder对象:

  • 确定objectName属性:若传入的attName属性为空串,则objectName为类名第一个字母小写 -- 注意:attrName。若目标方法的POJO属性使用了@ModelAttribute来修饰,则attrName为@ModelAttribute的value属性值
  • 确定target属性:
    • 在implicitModel中查找attrName对应的属性值,若存在,OK
    • 若不存在:则验证当前Handler是否使用了@SessionAttributes进行修饰,若使用了,则尝试从Session中获取attrName所对应的属性值,若session中没有对应属性值,则抛出异常
    • 若Handler没有使用@SessionAttributes进行修饰,或@SessionAttributes中没有使用value值制定的key和attrName相匹配。则通过反射创建POJO对象
      (2)SpringMVC把表单的请求参数赋给了WebDataBinder的target对应的属性
      (3)SpringMVC会把WebDataBinder的attrName和target给到implicitModel,进而传到request域对象中
      (4)把WebDataBinder的target作为参数传递给目标方法的入参

视图和视图解析器

  • 请求处理方法执行完成后,最终返回一个 ModelAndView对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个ModelAndView 对象,它包含了逻辑名和模型对象的视图
  • Spring MVC 借助视图解析器(ViewResolver)得到最终 的视图对象(View),最终的视图可以是 JSP ,也可能是Excel、JFreeChart 等各种表现形式的视图
  • 对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦

自定义视图

@Component
public class HelloView implements View {
    @Override
    public String getContentType() {
        return "html/text";
    }

    @Override
    public void render(Map<String, ?> map, javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
        httpServletResponse.getWriter().print("hello view");
    }
}
 <!-- 配置视图BeanNameViewResolver解析器,使用视图名字来解析视图 -->
    <!-- 通过order属性来定义视图解析器的优先级,order值越小优先级越高 -->
    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
        <property name="order" value="100"></property>
    </bean>

自定义类型转换器

springmvc不支持将字符串转换为日期格式

<!-- 注解驱动,配置转换器时要用到conversion-service这个属性 -->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>

<!-- 配置转换器工厂 -->
<bean id="conversionServiceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <!-- 配置多个转换器 -->
    <property name="converters">
        <list>
            <!-- 配置日期转换器 -->
            <bean class="com.wu.conversion.DataConveter"/>
        </list>
    </property>
</bean>
//泛型第一个为转换前的类型,后一个为转换后的类型
public class DataConveter implements Converter<String, Date> {

    //这里的s为要转换的字符串
    @Override
    public Date convert(String s) {
        try {
            if (s != null) {
                DateFormat df = new SimpleDateFormat("yyyy_MM-dd hh:mm-ss");
                return df.parse(s);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

数据校验 - JSR303

错误消息的显示

    <!--  显示所有的错误消息  -->
    <form:errors path="*"></form:errors>

    <!--  显示对应字段的错误消息  -->
    <input type="text" name="name">
    <form:errors path="name"></form:errors>

国际化定制错误消息

• 每个属性在数据绑定和数据校验发生错误时,都会生成一个对应的 FieldError 对象。

• 当一个属性校验失败后,校验框架会为该属性生成 4 个消息代码,这些代码以校验注解类名为前缀,结合modleAttribute、属性名及属性类型名生成多个对应的消息代码:例如 User 类中的 password 属性标准了一个 @Pattern 注解,当该属性值不满足 @Pattern 所定义的规则时, 就会产生以下 4 个错误代码:

– Pattern.user.password

– Pattern.password

– Pattern.java.lang.String

– Pattern

eg:

#i18n.properties
NotEmpty.Animal.name=名字不能为空

• 当使用 Spring MVC 标签显示错误消息时, Spring MVC 会查看WEB 上下文是否装配了对应的国际化消息,如果没有,则显示默认 的错误消息,否则使用国际化消息。

    <!-- 配置国际化资源文件 -->
    <bean id="resourceBundleMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="i18n"></property>
    </bean>

通过链接切换语言

    <!--  配置SessionLocaleResolver  -->
    <bean id="sessionLocaleResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
    <!-- 配置LocaleChangeInterceptor -->
    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
    </mvc:interceptors>
<a href="/i18n?locale=zh_CH">中文</a>
<a href="/i18n?locale=en_US">英文</a>

拦截器

    <mvc:interceptors>
        <!-- 配置拦截器作用(或者是不作用)的路径 -->
        <mvc:interceptor>
            <mvc:mapping path="/hello"/>
            <bean class="top.wu.controller.MyInterceptHandler"></bean>
        </mvc:interceptor>
        <!-- 配置LocaleChangeInterceptor -->
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
    </mvc:interceptors>

自定义拦截器

public class MyInterceptHandler implements HandlerInterceptor {


    /**
     * 该方法在目标方法之前被调用
     * 若返回值为true,则继续调用后续的拦截器和目标方法
     * 若返回值为false,则不会调用后续的拦截器和目标方法
     *
     * 可以考虑做权限,日志,事务等
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return false;
    }

    /**
     *调用目标方法之后,但渲染视图之前
     * 可以对请求域中的属性或视图做出修改
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 渲染视图之后被调用。释放资源
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
    <mvc:interceptors>
        <!-- 配置自定义拦截器 -->
        <bean class="top.wu.controller.MyInterceptHandler"></bean>
    </mvc:interceptors>

SpringMVC运行流程

image.png