最全面SSM三大框架之Spring MVC篇

Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。

先看项目目录,基于此目录配置:
<code>这里写图片描述</code>

  • -

Spring MVC之使用配置:

Spring-MVC.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
                        http://www.springframework.org/schema/context  
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd  
                        http://www.springframework.org/schema/mvc  
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">



    <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->
    <context:component-scan base-package="com.ws.webp.controller" />


    <!--避免IE执行AJAX时,返回JSON出现下载文件 -->
    <bean id="mappingJacksonHttpMessageConverter"
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>text/html;charset=UTF-8</value>
            </list>
        </property>
    </bean>
    <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->
    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="mappingJacksonHttpMessageConverter" />   <!-- JSON转换器 -->
            </list>
        </property>
    </bean>
    <!-- 定义跳转的文件的前后缀 ,视图模式配置-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
        <!-- <property name="prefix" value="/WEB-INF/jsp/" /> -->
        <property name="prefix" value="/pages/" />
        <property name="suffix" value=".jsp" />
        <property name="order" value="1" />
    </bean>

    <!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->
    <bean id="multipartResolver"  
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
        <!-- 默认编码 -->
        <property name="defaultEncoding" value="utf-8" />  
        <!-- 文件大小最大值 -->
        <property name="maxUploadSize" value="10485760000" />  
        <!-- 内存中的最大值 -->
        <property name="maxInMemorySize" value="40960" />  
    </bean> 


  <!-- 扩充了注解驱动,可以将请求参数绑定到控制器参数 --> 
    <mvc:annotation-driven/>
    <!-- 启用基于Spring的注解 -->
    <context:annotation-config/>
    <!-- 静态资源处理 -->
    <mvc:resources mapping="/script/**" location="/script/" />  
    <mvc:resources mapping="/app/**" location="/app/" />  
    <mvc:resources mapping="/css/**" location="/css/" />  
    <mvc:resources mapping="/images/**" location="/images/" /> 



    <!-- 国际化配置 -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> 
        <property name="basename"> 
            <value>message</value> 
        </property> 
        <property name="defaultEncoding"> 
            <value>UTF-8</value> 
        </property> 
    </bean> 


       <!-- 定义跳转的文件的前后缀 ,视图模式配置 FreeMarker模板 -->
<!--    <bean
        id="freemarkerViewResolver" class="com.lava.common.web.springmvc.SimpleFreeMarkerViewResolver" >
        <property name="prefix" value="/pages/" />
        <property name="suffix" value=".jsp" />
        <property name="contentType" value="text/html; charset=UTF-8"/>
        <property name="exposeRequestAttributes" value="true"/>
        <property name="exposeSessionAttributes" value="true"/>
        <property name="exposeSpringMacroHelpers" value="true"/>
        <property name="order" value="0" />
    </bean>

     <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value=""/>
        <property name="freemarkerSettings">
            <props>
                <prop key="tag_syntax">auto_detect</prop>
                <prop key="template_update_delay">5</prop>
                <prop key="defaultEncoding">UTF-8</prop>
                <prop key="url_escaping_charset">UTF-8</prop>
                <prop key="locale">zh_CN</prop>
                <prop key="boolean_format">true,false</prop>
                <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
                <prop key="date_format">yyyy-MM-dd</prop>
                <prop key="time_format">HH:mm:ss</prop>
                <prop key="number_format">0.######</prop>
                <prop key="whitespace_stripping">true</prop>
                空值处理<prop key="classic_compatible">true</prop>
                <prop key="auto_import">/WEB-INF/ftl/spring.ftl as s</prop>
            </props>
        </property>
    </bean> -->
  <!-- added by wangshuo end -->
</beans> 

注释很清楚。

 <mvc:resources mapping="/script/**" location="/script/" />  
 <!-- 上面配置后,即可在JSP页面中引入script文件件下的js文件 -->
<script type="text/javascript" src="<%=request.getContextPath() %>/script/jquery-1.9.1.js"></script>
注意:在使用SpringMVC框架的时候配置了静态资源访问<mvc:resources mapping="/resources/**" location="/WEB-INF/resources/" />后,发现访问页面出现404错误,注意是访问页面404,并不是静态资源访问404,后来发现我的spring-servlet.xml配置文件中的启用spring mvc 注解使用的是<context:annotation-config />,后来添加<mvc:annotation-driven/>后访问成功!

web.xml 配置:

<!-- Spring MVC servlet -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

最常用的视图解析器:InternalResourceViewResolver

<!-- 定义跳转的文件的前后缀 ,视图模式配置-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
        <property name="prefix" value="/WEB-INF/jsp/" />    
        <property name="suffix" value=".jsp" />
        <property name="order" value="1" />
    </bean>

当处理器返回“index”时,InternalResourceViewResolver解析器会自动添加前缀和后缀:/WEB-INF/jsp/index.jsp

注意:这里的order表示视图解析的优先级,数目越小优先级越大(即:0为优先级最高,所以优先进行处理视图),

InternalResourceViewResolver在项目中的优先级必须设置为最低,也就是order要最大。不然它会阻碍其他
视图解析器。为什么呢?

解释如下:
我们知道,当处理器返回逻辑视图时(也就是return “string”),要经过视图解析器链,前面的解析器能处理的,就不会继续往下传播。
如果不能处理就要沿着解析器链继续寻找,直到找到合适的视图解析器

但是对于解析器InternalResourceViewResolver来说,不管能不能解析它都不会返回null,也就是说它拦截了所有的逻辑视图,让后续的解析器得不到执行,所以InternalResourceViewResolver必须放在最后。

SpringMVC常用注解

代码示例:

@Controller  
@RequestMapping("/login")  
public class LoginController {
    private static Logger logger = Logger.getLogger(LoginController.class); 
    @Resource
    private IPersonService personService;

    @RequestMapping("/person")
    @ResponseBody
    private Object register(Person person){

       logger.debug("ws--register-------"); 
       person.setState(0);
       return ResponseUtils.sendSuccess(this.personService.registerPerson(person));      
    }

1、@Controller
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。

2、@RequestMapping

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

RequestMapping注解有六个属性,下面我们把她分成三类进行说明(下面有相应示例)。

1、 value, method;

value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);

method: 指定请求的method类型, GET、POST、PUT、DELETE等;

2、consumes,produces

consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

3、params,headers

params: 指定request中必须包含某些参数值是,才让该方法处理。

headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。

3、@Resource和@Autowired

@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。

1、共同点

两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。

2、不同点

(1)@Autowired

@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。
@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。
2)@Resource

@Resource默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。

4、@ModelAttribute和 @SessionAttributes

代表的是:该Controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。

@SessionAttributes即将值放到session作用域中,写在class上面。

5、@PathVariable

用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。

6、@requestParam

@requestParam主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter(“name”),它有三个常用参数:defaultValue = “0”, required = false, value = “isApp”;defaultValue 表示设置默认值,required 铜过boolean设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。
7、@ResponseBody

作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。

使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
8、@Component

相当于通用的注解,当不知道一些类归到哪个层时使用,但是不建议。
9、@Repository

用于注解dao层,在daoImpl类上面注解。

注解详情:http://www.cnblogs.com/leskang/p/5445698.html

Spring MVC 向页面传值-Map、Model和ModelMap

 @RequestMapping("/test")
 public String test(Map<String,Object> map,Model model,ModelMap modelMap){

     map.put("names", Arrays.asList("caoyc","zhh","cjx"));
     model.addAttribute("time", new Date());
     modelMap.addAttribute("city", "ChengDu");
     modelMap.put("gender", "male");
     return "hello";
 }

jsp页面

time:${param.time}
names:${param.names }
city:${param.city }
gender:${requestScope.gender }

spring mvc 请求转发和重定向

重定向和转发有一个重要的不同:当使用转发时,JSP容器将使用一个内部的方法来调用目标页面,新的页面继续处理同一个请求,而浏览器将不会知道这个过程。 与之相反,重定向方式的含义是第一个页面通知浏览器发送一个新的页面请求。因为,当你使用重定向时,浏览器中所显示的URL会变成新页面的URL, 而当使用转发时,该URL会保持不变。重定向的速度比转发慢,因为浏览器还得发出一个新的请求。同时,由于重定向方式产生了一个新的请求,所以经过一次重 定向后,request内的对象将无法使用。

怎么选择是重定向还是转发呢?通常情况下转发更快,而且能保持request内的对象,所以他是第一选择。但是由于在转发之后,浏览器中URL仍然指向开始页面,此时如果重载当前页面,开始页面将会被重新调用。如果你不想看到这样的情况,则选择转发。

转发和重定向的区别

不要仅仅为了把变量传到下一个页面而使用session作用域,那会无故增大变量的作用域,转发也许可以帮助你解决这个问题。

重定向:以前的request中存放的变量全部失效,并进入一个新的request作用域。

转发:以前的request中存放的变量不会失效,就像把两个页面拼到了一起。

        //1、请求重定向:// 重定向到toList请求


        //<1> 不带参数的重定向
        //方式一:使用ModelAndView
                    return new ModelAndView("redirect:/toList");
        //方式二:返回String
                    return "redirect:/ toList"; 

         //<2> 带参数的重定向
         //方式一:自己手动拼接url

                    return new ModelAndView("redirect:/toList?param1="+value1+"&param2="+value2);

                   // 弊端:传中文可能乱码

        // 方式二:用RedirectAttributes类
                      //使用addAttribute方法,自动给你拼接url

                     // 使用方法:

                      public String save(@ModelAttribute("form") Bean form,RedirectAttributes attr){

                          ...

                          attr.addAttribute("param", value);
                          return "redirect:/toList";
                      }

                      //在toList方法中可以通过获得参数的方式获取参数




         //2、请求转发:// 转发到toList请求

        //<1> 不带参数的转发
        //方式一:使用ModelAndView
                    return new ModelAndView("forward:/toList");
        // 方式二:返回String
                    return "forward:/toList"; 

        //<2> 带参数的转发
        //方式一:使用ModelAndView
                    return new ModelAndView("forward:/toList?param1="+value1+"&param2="+value2");
       // 方式二:返回String
          return "forward:/ toList?param1="+value1+"&param2="+value2"; 

SpringMVC存取Session的两种方法

//一
    @Controller  
    public class ManagerController {  

        @Resource  
        private ManagerService managerServiceImpl;  

        @RequestMapping(value = "manager/login.do",method = RequestMethod.GET)    
        public ModelAndView login(ManagerModel managerModel,HttpSession httpSession){  

            ManagerModel manager = managerServiceImpl.getManager(managerModel);  
            if(manager!=null){  
                manager.setPassword("");  
                httpSession.setAttribute("manager", manager);  
                return new ModelAndView(new RedirectView("../admin/main.jsp"));  
            }else{  
                return new ModelAndView(new RedirectView("../admin/login.jsp"));  
            }  
        }  

        @RequestMapping(value = "manager/logout.do",method = RequestMethod.GET)  
        public String logout(HttpSession httpSession){  
            httpSession.getAttribute("manager");  
            return "success";  
        }  
    }  

//二
    @Controller  
    @SessionAttributes("manager")  
    public class ManagerController {  

        @Resource  
        private ManagerService managerServiceImpl;  

        @RequestMapping(value = "manager/login.do",method = RequestMethod.GET)    
        public ModelAndView login(ManagerModel managerModel,ModelMap model){  

            ManagerModel manager = managerServiceImpl.getManager(managerModel);  
            if(manager!=null){  
                manager.setPassword("");  
                model.addAttribute("manager", manager);  
                return new ModelAndView(new RedirectView("../admin/main.jsp"));  
            }else{  
                return new ModelAndView(new RedirectView("../admin/login.jsp"));  
            }  
        }  

        @RequestMapping(value = "manager/logout.do",method = RequestMethod.GET)  
        public String logout(@ModelAttribute("manager")ManagerModel managerModel){  
            return "success";  
        }  
    }  

SpringMVC配置拦截器示例

springmvc.xml:

 <!--拦截 -->
    <mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/login/**" />
        <bean class="com.lava.lavafaq.springmvc.LoginInterceptor">
         <property name="excludeUrls">
                <list>
                   <value>/login/loginHtml</value>
                    <value>/login/login</value>                 
                </list>
            </property>   
        </bean>
    </mvc:interceptor>
 </mvc:interceptors> 
package com.lava.lavafaq.springmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.UrlPathHelper;


public class LoginInterceptor implements HandlerInterceptor {

    private static Logger logger = Logger.getLogger(LoginInterceptor.class); 
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        // TODO Auto-generated method stub
             // 不在验证的范围内
          String uri = getURI(request);             
           if (exclude(uri)) {        
             return true;
           }

        HttpSession session = request.getSession();
        String username = (String) session.getAttribute("username");
        logger.info("Pedirect to login page session username="+username);
        if (username == null|| username.length()==0 ) {          
            logger.info("Pedirect to login page");
            response.sendRedirect(getLoginUrl(request,"/login/loginHtml"));
            return false;
        }
        return true;

    }

    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub

    }


    /**
     * 获得第三个路径分隔符的位置
     * 
     * @param request
     * @throws IllegalStateException
     *             访问路径错误,没有三(四)个'/'
     *    http://localhost:8080/lavaFAQ/login/loginHtml       
     *    getURI=/login/loginHtml uri=/lavaFAQ/login/loginHtml ctxPath=/lavaFAQ
     */
    private static String getURI(HttpServletRequest request)
            throws IllegalStateException {
        UrlPathHelper helper = new UrlPathHelper();
        String uri = helper.getOriginatingRequestUri(request);
        String ctxPath = helper.getOriginatingContextPath(request);
        int start = 0;
        if (!StringUtils.isBlank(ctxPath)) {
            start = ctxPath.length();
        }
        logger.info("getURI="+uri.substring(start)+" uri="+uri+" ctxPath="+ctxPath);
        return uri.substring(start);
    }

    private boolean exclude(String uri) {
        if (excludeUrls != null) {
            for (String exc : excludeUrls) {
                if (uri.startsWith(exc)) {
                    return true;
                }
            }
        }
        return false;
    }
    //lavaFAQ---request.getContextPath()    
    private String getLoginUrl(HttpServletRequest request,String loginUrl) {
        StringBuilder buff = new StringBuilder();
        if (loginUrl.startsWith("/")) {
            String ctx = request.getContextPath();
            if (!StringUtils.isBlank(ctx)) {
                buff.append(ctx).append(loginUrl);
            }
        }
        logger.info("getLoginUrl="+buff.toString());
        return buff.toString();
    }

    private String[] excludeUrls;

    public void setExcludeUrls(String[] excludeUrls) {
        this.excludeUrls = excludeUrls;
    }

}
//登录请求   
    @RequestMapping("/login")   
    private String login(Person person,ModelMap modelMap,HttpSession httpSession){      
        String result = this.personService.loginPerson(person);
        if(result.equals(Canstants.loginSuccess)){
            //登录成功存储Session         
             httpSession.setAttribute("username", person.getMail()); 
             return "homepage"; 
        }
         modelMap.addAttribute("result",result);        
       return "redirect:/login/loginHtml";   
    }

spring-mvc的Conveter和Formatter

Spring的Converter可以将一种类型转换成另一种类型。在使用时,必须编写一个实现org.springframework.core.convert.converter.Converter接口的java类。这个接口的声明如下

public interface Converter<S, T> {
    T convert(S var1);
}

//这里的S表示源类型,T表示目标类型。下面展示了一个将String类型转换成Date类型的Converter
public class DateConverter implements Converter<String, Date> {

    public static final DateFormat DF_LONG = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");
    public static final DateFormat DF_SHORT = new SimpleDateFormat("yyyy-MM-dd");
    public static final DateFormat DF_YEAR = new SimpleDateFormat("yyyy");
    public static final DateFormat DF_MONTH = new SimpleDateFormat("yyyy-MM");
    /**
     * 短类型日期长度
     */
    public static final int SHORT_DATE = 10;

    public static final int YEAR_DATE = 4;

    public static final int MONTH_DATE = 7;

    @Override
    public Date convert(String text) {
        text = text.trim();
        if (!StringUtils.hasText(text)) {
            return null;
        }

        try {
            if (text.length() <= YEAR_DATE) {
                return DF_YEAR.parse(text);
            } else if (text.length() <= MONTH_DATE) {
                return DF_MONTH.parse(text);
            } else if (text.length() <= SHORT_DATE) {
                return DF_SHORT.parse(text);
            } else {
                return DF_LONG.parse(text);
            }
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        return null;
    }
}

为了使用Spring MVC应用程序定制的Converter,需要在配置文件中添加一个conversionService bean。Bean的类名称必须为org.springframework.context.support.ConversionServiceFactoryBean。这个bean必须包含一个converters属性,它列出要在应用程序中使用的所有定制Converter。

  <!-- 日期全局转换配置 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">    
         <property name="converters">    
             <list>    
                 <bean class="com.lava.lavafaq.springmvc.DateConverter" />    
             </list>    
         </property>    
     </bean>  

之后,还需要给annotation-driven元素的conversion-service属性赋上bean名称,如下

 <mvc:annotation-driven conversion-service="conversionService" />  

Formatter和Converter一样,也是将一种类型转换成另一种类型。但是,Formatter的源类型必须是一个String。不在追述。

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页