Java之Spring mvc詳解(非原創)

文章大綱

1、Spring mvc介紹
2、Spring mvc代碼實戰
3、項目源碼下載
4、參考文章javascript

 

1、Spring mvc介紹

1. 什麼是springmvc

  springmvc是spring框架的一個模塊,springmvc和spring無需經過中間整合層進行整合。springmvc是一個基於mvc的web框架。php

 

2. mvc設計模式在b/s系統 下的應用

 

3. Spring mvc框架執行流程

 

  第一步:發起請求到前端控制器(DispatcherServlet)
  第二步:前端控制器請求HandlerMapping查找 Handler,能夠根據xml配置、註解進行查找,經過@RequestMapping(value = "/test")中的test進行查找
  第三步:處理器映射器HandlerMapping向前端控制器返回Handler
  第四步:前端控制器調用處理器適配器去執行Handler
  第五步:處理器適配器去執行Handler
  第六步:Handler執行完成給適配器返回ModelAndView
  第七步:處理器適配器向前端控制器返回ModelAndView,ModelAndView是springmvc框架的一個底層對象,包括 Model和view
  第八步:前端控制器請求視圖解析器去進行視圖解析,根據邏輯視圖名解析成真正的視圖(jsp)
  第九步:視圖解析器向前端控制器返回View
  第十步:前端控制器進行視圖渲染,視圖渲染將模型數據(在ModelAndView對象中)填充到request域
  第十一步:前端控制器向用戶響應結果css

4. Spring mvc組件介紹

(1)前端控制器DispatcherServlet(不須要程序員開發)
做用接收請求,響應結果,至關於轉發器,中央處理器。
有了DispatcherServlet減小了其它組件之間的耦合度。html

(2)處理器映射器HandlerMapping(不須要程序員開發)
做用:根據請求的url查找Handler前端

(3)處理器適配器HandlerAdapter
做用:按照特定規則(HandlerAdapter要求的規則)去執行Handlerjava

(4)處理器Handler(須要程序員開發)
注意:編寫Handler時按照HandlerAdapter的要求去作,這樣適配器才能夠去正確執行Handlergit

(5)視圖解析器View resolver(不須要程序員開發)
做用:進行視圖解析,根據邏輯視圖名解析成真正的視圖(view)程序員

(6)視圖View(須要程序員開發jsp)
View是一個接口,實現類支持不一樣的View類型(jsp、freemarker、pdf...)github

2、Spring mvc代碼實戰

  Spring mvc常見使用功能有數據交互方式(ModelAndView和JSON)、靜態資源的解析、參數校驗、全局異常處理、攔截器、上傳圖片等。web

1. 建立maven的javaweb項目

文章重點在於講解Spring mvc功能,所以建立項目方式不進行深刻講解,建立後的項目目錄以下:

 

2. Spring mvc基本配置

2.1 在pom.xml添加maven依賴

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>springmvc_demo</groupId> <artifactId>springmvc_demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name/> <description/> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- spring版本號 --> <spring.version>4.2.5.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.2</version> </dependency> <dependency> <groupId>org.apache.openejb</groupId> <artifactId>javaee-api</artifactId> <version>5.0-1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency> <!-- 分頁 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.4</version> </dependency> <!--測試包--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- c3p0數據庫鏈接池 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- commons工具包 --> <!--圖片上傳相關的--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2</version> </dependency> <dependency> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-math3</artifactId> <version>3.2</version> </dependency> <dependency> <groupId>commons-validator</groupId> <artifactId>commons-validator</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>commons-httpclient</groupId> <artifactId>commons-httpclient</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging-api</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.6</version> </dependency> <!-- 添加spring核心依賴 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.2</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.9</version> </dependency> <!-- 日誌相關工具類導入 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.7</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.7</version> </dependency> <!-- validation校驗--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <!-- validation校驗--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.0.Final</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project> 

2.2 web.xml中配置

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name></display-name> <!-- 解決post請求中文亂碼 --> <filter> <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- (1)DispatcherServlet是前端控制器設計模式的實現,提供Spring Web MVC的集中訪問點, 並且負責職責的分派,並且與Spring IoC容器無縫集成 (2)load-on-startup:表示啓動容器時初始化該Servlet; (3)url-pattern:表示哪些請求交給Spring Web MVC處理, 「/」 是用來定義默認servlet映射的。 也能夠如「*.html」表示攔截全部以html爲擴展名的請求。 --> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- 若是不配置contextConfigLocation,則默認加載WEB-INFO下面的applicationContext.xml --> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- 配置方式有幾種 1. *.action,能夠訪問以.action結尾,由DispatcherServlet進行解析 2. /,全部訪問的地址由DispatcherServlet進行解析,對於靜態文件的解析須要配置不讓DispatcherServlet進行解析 3. /*,這樣配置不對,使用這種配置,最終要轉發到一個jsp頁面,仍然由DispatcherServlet解析jsp,不能根據jsp找到Handler,結果錯誤 --> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> 

舒適提示:上面代碼中解決了POST中文亂碼問題,且添加了前端控制器等相應配置。

2.3 中文亂碼解決
POST方式亂碼解決辦法是在web.xml中添加如下代碼

<!-- 解決post請求中文亂碼 --> <filter> <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 

GET方式亂碼解決方法以下:
(1)修改tomcat配置文件添加編碼與工程編碼一致,以下:

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

(2)ISO8859-1是tomcat默認編碼,須要將tomcat編碼後的內容按utf-8編碼

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

2.4 resources文件夾下配置
新建配置文件logback.xml進行日誌配置

<!-- ch.qos.logback.classic.filter.ThresholdFilter 臨界值過濾器, 過濾掉低於指定臨界值的日誌 ch.qos.logback.classic.filter.LevelFilter 將過濾器的日誌級別配置爲INFO,全部INFO級別的日誌交給appender處理,非INFO級別的日誌,被過濾掉。 --> <configuration> <property name="APP_Name" value="ssm_Demo" /> //這裏爲此項目的日誌文件夾名 <property name="log.dir" value="F:/home"></property> //這裏爲日誌的存儲地址 <timestamp key="bySecond" datePattern="yyyyMMdd HHmmss"/> <contextName>${APP_Name}</contextName> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} [%file:%line] - %msg%n</Pattern> </layout> </appender> <!-- 按日期和大小區分的滾動日誌 --> <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.dir}/${APP_Name}/info/info.%d{yyyy-MM-dd}-%i.log</fileNamePattern> <maxHistory>30</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!-- 按日期和大小區分的滾動日誌 --> <appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 必須指定,不然不會往文件輸出內容 --> <encoder> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern> </encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!-- 必須要指定rollingPolicy 與 triggeringPolicy 屬性 不然不會生成文件--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.dir}/${APP_Name}/debug/debug.%d{yyyy-MM-dd}-%i.log</fileNamePattern> <maxHistory>30</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!-- error級別只按日期滾動生成日誌 --> <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 必須指定,不然不會往文件輸出內容 --> <encoder> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> <!-- <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch>--> </filter> <!-- 必須要指定rollingPolicy 與 triggeringPolicy 屬性 不然不會生成文件--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.dir}/${APP_Name}/error/error.%d{yyyy-MM-dd}-%i.log</fileNamePattern> <maxHistory>30</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 默認值是10MB。 --> <!-- <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>5MB</maxFileSize> </triggeringPolicy> --> </appender> <!-- 滾動記錄文件 --> <appender name="MONITOR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern> </encoder> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.dir}/${APP_Name}/monitor/monitor.%d{yyyy-MM-dd}-%i.log</fileNamePattern> <maxHistory>30</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <logger name="org" level="INFO" /> <!--將org包下面的全部日誌級別設爲了ERROR --> <logger name="monitor" additivity="false" level="DEBUG" /> <logger name="monitor" additivity="false" level="DEBUG"> <appender-ref ref="MONITOR" /> </logger> <root level="DEBUG"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE_INFO" /> <appender-ref ref="FILE_DEBUG" /> //上線時 這個需註釋掉,debug級別的日誌 <appender-ref ref="FILE_ERROR" /> </root> </configuration> 

添加spring mvc的xml配置
  在resources文件夾下新建spring文件夾,新建applicationContext.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 這樣classpath:properties目錄下的.properties文件就會被spring加載 --> <context:property-placeholder location="classpath:properties/*.properties"/> <!-- 對於spring配置文件的編寫,我想,對於經歷過龐大項目的人,都有那種恐懼的心理,太多的配置文件。 不過,分模塊都是大多數人能想到的方法,可是,怎麼分模塊,那就是仁者見仁,智者見智了。個人策略是使用import。 下面的配置, 再resources/spring目錄下的以applicationContext開頭的xml文件將所有被加載 --> <import resource="applicationContext-*.xml"/> </beans> 

新建applicationContext-web.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: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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> </beans> 

舒適提示:
咱們可能會在其餘的項目中看到ssm(Spring、Spring mvc、mybatis)的配置文件都在同一個xml文件中,可是這樣很差管理,在該文章中,咱們的spring文件夾中的配置文件採用解耦方式進行配置,在web.xml中進行總的配置加載,再分別加載持久層、應用層、邏輯層,正常配置後的文件結構以下:

 

3. Spring mvc建立兩種方式

3.1 經過實現Controller方式
在applicationContext-web.xml中添加如下代碼,testController2爲該Controller訪問的地址

<!--配置Handler --> <bean name="/testController2" class="com.wxc.controller.TestController2" /> 

在WEB-INF文件夾下新建jsp文件夾,以後新建MyJsp.jsp

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>this is a new page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> this is a new page<br> </body> </html> 

在com.wxc.controller文件夾下新建TestController2類並實現Controller

package com.wxc.controller; import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 測試spring mvc建立第二種方式 經過實現Controller,且在xml文件中進行配置 */ public class TestController2 implements Controller { public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception { //返回ModelView ModelAndView modelAndView = new ModelAndView(); //指定視圖 modelAndView.setViewName("/WEB-INF/jsp/items/MyJsp.jsp"); return modelAndView; } } 

建立後文件目錄以下:

 

運行項目,訪問結果以下:

 

3.2 經過註解方式
在applicationContext-web.xml添加如下代碼:

<!-- 開啓註解映射的支持 開啓mvc註解 至關於 <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="com.wxc.controller"/> 

在com.wxc.controller包下建立TestController.java

package com.wxc.controller; import com.wxc.vo.TestVo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import java.util.HashMap; import java.util.Map; /** * 測試springmvc第一種方式 註解方式 */ @Controller @RequestMapping("/testController") public class TestController { @RequestMapping(value = "/test") @ResponseBody public TestVo test() { System.out.println("接口請求,已處理"); TestVo testVo = new TestVo("1", "成功"); return testVo; } @RequestMapping(value = "/test2") @ResponseBody public ModelAndView test2(){ //返回ModelView ModelAndView modelAndView = new ModelAndView(); //指定視圖 modelAndView.setViewName("/WEB-INF/jsp/items/MyJsp.jsp"); return modelAndView; } /** * 測試返回集合 * @return */ @RequestMapping(method = RequestMethod.POST, value="/test3") @ResponseBody public Map<String, Object> test3() { Map<String, Object> outMap = new HashMap<String, Object>(); outMap.put("測試1", "ceshi1"); outMap.put("測試2","ceshi2"); return outMap; } } 

運行結果以下:

 

4. Spring mvc應用層數據交互方式

  應用層數據交互方式包括jsp(ModelAndView)與JSON,其中返回值爲ModelAndView表示返回jsp,若是添加@ResponseBody註解表示返回json數據,具體查看3.2中代碼。

5. Spring mvc實現文件上傳與訪問

5.1 配置tomncat虛擬磁盤目錄訪問文件
在tomcat的配置文件server.xml下添加如下代碼:

<Context docBase="G:\ssm\spring mvc\daima\picture" path="/picture" reloadable="false"/> 

添加後截圖以下:

 

舒適提示:
(1)docBase表明本地磁盤的文件地址
(2)path表示訪問的目錄地址

5.2 pom.xml文件添加maven依賴

<!--圖片上傳相關的--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> 

5.3 applicationContext-web.xml添加配置

<!-- 文件上傳 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 設置上傳文件的最大尺寸爲5MB --> <property name="maxUploadSize"> <value>5242880</value> </property> </bean> 

5.4 新建測試類PictureController.java

package com.wxc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.util.UUID; /** * 圖片上傳相關 * * 第一步:配置tomncat虛擬目錄訪問圖片 * * 第二步:導入maven相關jar包 * * 第三步:xml中配置相關參數 * */ @Controller @RequestMapping("/pictureController") public class PictureController { //商品修改提交 @RequestMapping("/editItemSubmit") @ResponseBody public String editItemSubmit(MultipartFile pictureFile)throws Exception { //原始文件名稱 String pictureFile_name = pictureFile.getOriginalFilename(); //新文件名稱 String newFileName = UUID.randomUUID().toString() + pictureFile_name.substring(pictureFile_name.lastIndexOf(".")); //上傳圖片 File uploadPic = new java.io.File("G:/ssm/spring mvc/daima/picture/" + newFileName); if (!uploadPic.exists()) { uploadPic.mkdirs(); } //向磁盤寫文件 pictureFile.transferTo(uploadPic); return "true"; } } 

運行結果以下:

 
 
 

6. 全局異常處理

  經過 @ControllerAdvice 註解,咱們能夠在一個地方對全部 @Controller 註解的控制器進行管理。註解了 @ControllerAdvice 的類的方法可使用 @ExceptionHandler、 @InitBinder、 @ModelAttribute 註解到方法上,這對全部註解了 @RequestMapping 的控制器內的方法都有效。
  本文經過全局統一的異常處理將自定義錯誤碼以json的形式發送給前端。

6.1 新建統一返回結果類 ApiResult.java
定義一個統一結果返回類,最終須要將這個結果類的內容返回給前端。

package com.wxc.vo;

import com.wxc.enums.ResultCode; /** * Api統一的返回結果類 */ public class ApiResult { /** * 結果碼 */ private String code; /** * 結果碼描述 */ private String msg; public ApiResult() { } public ApiResult(ResultCode resultCode) { this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); } /** * 生成一個ApiResult對象, 並返回 * * @param resultCode * @return */ public static ApiResult of(ResultCode resultCode) { return new ApiResult(resultCode); } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } @Override public String toString() { return "ApiResult{" + "code='" + code + '\'' + ", msg='" + msg + '\'' + '}'; } } 

6.2 新建錯誤碼枚舉類 ResultCode.java
有了 ApiResult ,接下來須要定義一個枚舉類, 來包含全部自定義的結果碼

package com.wxc.enums;

/** * 錯誤碼 */ public enum ResultCode { /** * 成功 */ SUCCESS("0", "success"), /** * 未知錯誤 */ UNKNOWN_ERROR("0x10001", "unkonwn error"), /** * 用戶名錯誤或不存在 */ USERNAME_ERROR("0x10002", "username error or does not exist"), /** * 密碼錯誤 */ PASSWORD_ERROR("0x10003", "password error"), /** * 用戶名不能爲空 */ USERNAME_EMPTY("0x10004", "username can not be empty"); /** * 結果碼 */ private String code; /** * 結果碼描述 */ private String msg; ResultCode(String code, String msg) { this.code = code; this.msg = msg; } public String getCode() { return code; } public String getMsg() { return msg; } } 

6.3 自定義業務異常類 BusinessRuntimeException.java
接下來須要定義咱們本身的業務異常類,之後和業務相關的異常統統拋出這個異常類,咱們將錯誤碼枚舉變量的值存於其中。

package com.wxc.exception;

import com.wxc.enums.ResultCode; /** * 自定義業務異常 */ public class BusinessRuntimeException extends RuntimeException { /** * 結果碼 */ private String code; /** * 結果碼描述 */ private String msg; /** * 結果碼枚舉 */ private ResultCode resultCode; public BusinessRuntimeException(ResultCode resultCode) { super(resultCode.getMsg()); this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); this.resultCode = resultCode; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public ResultCode getResultCode() { return resultCode; } public void setResultCode(ResultCode resultCode) { this.resultCode = resultCode; } } 

6.4 新建全局異常處理類 GlobalExceptionResolver.java
說明:
(1)經過 @ControllerAdvice 指定該類爲 Controller 加強類。
(2)經過 @ExceptionHandler 自定捕獲的異常類型。
(3)經過 @ResponseBody 返回 json 到前端
(4)注意一點:被@ControllerAdvice註解的全局異常處理類也是一個 Controller ,咱們須要配置掃描路徑,確保可以掃描到這個Controller。

package com.wxc.exception; import com.wxc.enums.ResultCode; import com.wxc.vo.ApiResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * 全局Controller層異常處理類 */ @ControllerAdvice public class GlobalExceptionResolver { private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionResolver.class); /** * 處理全部不可知異常 * * @param e 異常 * @return json結果 */ @ExceptionHandler(Exception.class) @ResponseBody public ApiResult handleException(Exception e) { // 打印異常堆棧信息 LOG.error(e.getMessage(), e); return ApiResult.of(ResultCode.UNKNOWN_ERROR); } /** * 處理全部業務異常 * * @param e 業務異常 * @return json結果 */ @ExceptionHandler(BusinessRuntimeException.class) @ResponseBody public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) { // 不打印異常堆棧信息 LOG.error(e.getMsg()); return ApiResult.of(e.getResultCode()); } } 

配置完成後的項目結構以下:

 

6.5 新建測試類CatchController.java

package com.wxc.controller; import com.wxc.enums.ResultCode; import com.wxc.exception.BusinessRuntimeException; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * 測試異常拋出 * * 參考博客:https://blog.csdn.net/hbtj_1216/article/details/81102063 */ @Controller @RequestMapping("/catchController") public class CatchController { /** * 測試返回異常信息 * @return */ @RequestMapping(value = "/test") public void test() { throw new BusinessRuntimeException(ResultCode.USERNAME_ERROR); } } 

6.6 運行結果以下:

 

7. Spring mvc參數綁定

7.1 支持類型介紹
spring mvc支持的綁定方式包括如下:
默認支持的參數類型
處理器形參中添加以下類型的參數處理適配器會默認識別並進行賦值。
(1)HttpServletRequest:經過request對象獲取請求信息
(2)HttpServletResponse:經過response處理響應信息
(3)HttpSession:經過session對象獲得session中存放的對象
(4)Model/ModelMap:ModelMap是Model接口的實現類,經過Model或ModelMap向頁面傳遞數據,以下:

簡單類型
包括布爾類型、字符串、單雙精度、整型等,下面重點講解@RequestParam
經過@RequestParam對簡單類型的參數進行綁定。
若是不使用@RequestParam,要求request傳入參數名稱和controller方法的形參名稱一致,方可綁定成功。
若是使用@RequestParam,不用限制request傳入參數名稱和controller方法的形參名稱一致。
經過required屬性指定參數是否必需要傳入,若是設置爲true,沒有傳入參數,報下邊錯誤:

 
 

pojo
將pojo對象中的屬性名於傳遞進來的屬性名對應,若是傳進來的參數名稱和對象中的屬性名稱一致則將參數值設置在pojo對象中

頁面定義以下;
            
              <input type="text" name="name"/> <input type="text" name="price"/> Contrller方法定義以下: @RequestMapping("/editItemSubmit") public String editItemSubmit(Items items)throws Exception{ System.out.println(items); 

自定義參數綁定

集合綁定

7.2 建立測試類ParameterBindingController.java

package com.wxc.controller; import com.wxc.vo.PojoVo; import com.wxc.vo.TestVo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap; import java.util.Map; /** * 講解spring mvc參數綁定 * spring mvc支持的綁定方式包括: * 1. 默認支持的參數類型 * 處理器形參中添加以下類型的參數處理適配器會默認識別並進行賦值。 (1)HttpServletRequest:經過request對象獲取請求信息 (2)HttpServletResponse:經過response處理響應信息 (3)HttpSession:經過session對象獲得session中存放的對象 (4)Model/ModelMap:ModelMap是Model接口的實現類,經過Model或ModelMap向頁面傳遞數據,以下: (2)//調用service查詢商品信息 Items item = itemService.findItemById(id); model.addAttribute("item", item); 頁面經過${item.XXXX}獲取item對象的屬性值。 使用Model和ModelMap的效果同樣,若是直接使用Model,springmvc會實例化ModelMap。 * 2. 簡單類型 * 包括布爾類型、字符串、單雙精度、整型等,下面重點講解@RequestParam * 使用@RequestParam經常使用於處理簡單類型的綁定。 * * value:參數名字,即入參的請求參數名字,如value=「item_id」表示請求的參數區中的名字爲item_id的參數的值將傳入; * required:是否必須,默認是true,表示請求中必定要有相應的參數,不然將報; * TTP Status 400 - Required Integer parameter 'XXXX' is not present * * defaultValue:默認值,表示若是請求中沒有同名參數時的默認值 * * 定義以下: * public String editItem(@RequestParam(value="item_id",required=true) String id) { * * } * * 形參名稱爲id,可是這裏使用value=" item_id"限定請求的參數名爲item_id,因此頁面傳遞參數的名必須爲item_id。 * 注意:若是請求參數中沒有item_id將跑出異常: * HTTP Status 500 - Required Integer parameter 'item_id' is not present * * 這裏經過required=true限定item_id參數爲必需傳遞,若是不傳遞則報400錯誤,可使用defaultvalue設置默認值,即便required=true也能夠不傳item_id參數值 * 3. pojo * 將pojo對象中的屬性名於傳遞進來的屬性名對應,若是傳進來的參數名稱和對象中的屬性名稱一致則將參數值設置在pojo對象中 * * 頁面定義以下; * * <input type="text" name="name"/> * <input type="text" name="price"/> * * Contrller方法定義以下: * * @RequestMapping("/editItemSubmit") * public String editItemSubmit(Items items)throws Exception{ * System.out.println(items); * 請求的參數名稱和pojo的屬性名稱一致,會自動將請求參數賦值給pojo的屬性。 * 4. 自定義參數綁定 * * 5. 集合類 * */ @Controller @RequestMapping("/parameterBindingController") public class ParameterBindingController { //method = RequestMethod.GET表示限定只能經過get方式進行訪問,若是經過Post訪問則報錯: //HTTP Status 405 - Request method 'POST' not supported //返回值是json數據,字符編碼爲utf-8 @RequestMapping(method = RequestMethod.GET, value="/test") @ResponseBody public TestVo test(int id, @RequestParam(value="item_name",required=true) String name) { TestVo testVo = new TestVo(id+"", name); return testVo; } //method = RequestMethod.GET表示限定只能經過get方式進行訪問,若是經過Post訪問則報錯: //HTTP Status 405 - Request method 'POST' not supported //返回值是json數據,字符編碼爲utf-8 @RequestMapping(method = RequestMethod.POST, value="/test2") @ResponseBody public PojoVo test2(PojoVo vo) { return vo; } } 

8. Spring mvc攔截器

8.1 applicationContext-web.xml添加如下配置

<!--攔截器 --> <mvc:interceptors> <!--多個攔截器,順序執行 --> <mvc:interceptor> <!-- /**表示全部url包括子url路徑 --> <mvc:mapping path="/**"/> <bean class="com.wxc.interceptor.HandlerInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.wxc.interceptor.HandlerInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors> 

8.2 新建攔截器
HandlerInterceptor1.java

package com.wxc.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** *Description:測試攔截器1 */ public class HandlerInterceptor1 implements HandlerInterceptor { //進入 Handler方法以前執行 //用於身份認證、身份受權 //好比身份認證,若是認證經過表示當前用戶沒有登錄,須要此方法攔截再也不向下執行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("HandlerInterceptor1...preHandle"); //return false表示攔截,不向下執行 //return true表示放行 return true; } //進入Handler方法以後,返回modelAndView以前執行 //應用場景從modelAndView出發:將公用的模型數據(好比菜單導航)在這裏傳到視圖,也能夠在這裏統一指定視圖 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("HandlerInterceptor1...postHandle"); } //執行Handler完成執行此方法 //應用場景:統一異常處理,統一日誌處理 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("HandlerInterceptor1...afterCompletion"); } } 

HandlerInterceptor2.java

package com.wxc.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** Description:測試攔截器2 */ public class HandlerInterceptor2 implements HandlerInterceptor { //進入 Handler方法以前執行 //用於身份認證、身份受權 //好比身份認證,若是認證經過表示當前用戶沒有登錄,須要此方法攔截再也不向下執行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("HandlerInterceptor2...preHandle"); //return false表示攔截,不向下執行 //return true表示放行 return true; } //進入Handler方法以後,返回modelAndView以前執行 //應用場景從modelAndView出發:將公用的模型數據(好比菜單導航)在這裏傳到視圖,也能夠在這裏統一指定視圖 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("HandlerInterceptor2...postHandle"); } //執行Handler完成執行此方法 //應用場景:統一異常處理,統一日誌處理 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("HandlerInterceptor2...afterCompletion"); } } 

8.3 建立後項目結構以下:

 

8.4 隨便訪問項目接口

 
 

9. Spring mvc之參數校驗

9.1 校驗理解
項目中,一般使用較可能是前端的校驗,好比頁面中js校驗。對於安全要求較高點建議在服務端進行校驗。
服務端校驗:
控制層conroller:校驗頁面請求的參數的合法性。在服務端控制層conroller校驗,不區分客戶端類型(瀏覽器、手機客戶端、遠程調用)
業務層service(使用較多):主要校驗關鍵業務參數,僅限於service接口中使用的參數。
持久層dao:通常是不校驗的。

9.2 pom.xml添加maven依賴

<!-- validation校驗--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <!-- validation校驗--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.0.Final</version> </dependency> 

9.3 applicationContext-web.xml配置校驗器

<!-- 校驗器 --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <!-- hibernate校驗器--> <property name="providerClass" value="org.hibernate.validator.HibernateValidator" /> <!-- 指定校驗使用的資源文件,在文件中配置校驗錯誤信息,若是不指定則默認使用classpath下的ValidationMessages.properties --> <property name="validationMessageSource" ref="messageSource" /> </bean> <!-- 校驗錯誤信息配置文件 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- 資源文件名--> <property name="basenames"> <list> <value>classpath:CustomValidationMessages.properties</value> </list> </property> <!-- 資源文件編碼格式 --> <property name="fileEncodings" value="utf-8" /> <!-- 對資源文件內容緩存時間,單位秒 --> <property name="cacheSeconds" value="120" /> </bean> 

9.4 CustomValidationMessages.properties添加錯誤信息

#\u6dfb\u52a0\u6821\u9a8c\u9519\u8bef\u63d0\u4ea4\u4fe1\u606f items.name.length.error=\u8bf7\u8f93\u51651\u523030\u4e2a\u5b57\u7b26\u7684\u5546\u54c1\u540d\u79f0 items.createtime.isNUll=\u8bf7\u8f93\u5165 \u5546\u54c1\u7684\u751f\u4ea7\u65e5\u671f 

9.5 建立測試實體類ValidationVo.java

package com.wxc.vo; import javax.validation.constraints.Size; /** * 測試校驗的實體類 */ public class ValidationVo { private Integer id; //校驗名稱在1到30字符中間 //message是提示校驗出錯顯示的信息 @Size(min=1,max=30,message="{items.name.length.error}") private String name; public Integer getId() { return id; } public String getName() { return name; } public void setId(Integer id) { this.id = id; } public void setName(String name) { this.name = name; } public ValidationVo(Integer id, String name) { this.id = id; this.name = name; } public ValidationVo() { } } 

9.6 建立校驗測試類ValidationController.java

package com.wxc.controller; import com.wxc.enums.ResultCode; import com.wxc.exception.BusinessRuntimeException; import com.wxc.vo.ValidationVo; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; /** * 校驗測試類 */ @Controller @RequestMapping("/validationController") public class ValidationController { @RequestMapping(value="/test") @ResponseBody public ValidationVo test(@Validated ValidationVo vo, BindingResult bindingResult) { if(bindingResult.hasErrors()) { //實際開發採用採用下面方式獲取錯誤信息 //輸出錯誤信息 List<ObjectError> allErrors = bindingResult.getAllErrors(); for (ObjectError objectError : allErrors) { // 輸出錯誤信息 System.out.println(objectError.getDefaultMessage()); } throw new BusinessRuntimeException(ResultCode.USERNAME_ERROR); } return vo; } } 

運行及訪問結果以下
(1)校驗經過狀況:

 

(2)校驗不經過狀況:

 

10. Spring mvc配置靜態資源訪問

  咱們在配置前端控制器時候,多是全部資源都進行攔截,因此致使靜態資源沒法訪問,因此須要經過如下方式配置能夠直接訪問靜態資源
10.1 WEB-INF新建文件夾image,並存放photo.png

 

10.2 applicationContext-web.xml添加配置

<mvc:resources location="/WEB-INF/image/" mapping="/image/**" /> 

10.3 運行後訪問結果以下:

 

11. Springmvc和struts2的區別

(1)springmvc基於方法開發的,struts2基於類開發的。
springmvc將url和controller方法映射。映射成功後springmvc生成一個Handler對象,對象中只包括了一個method。方法執行結束,形參數據銷燬。springmvc的controller開發相似service開發。
(2)springmvc能夠進行單例開發,而且建議使用單例開發,struts2經過類的成員變量接收參數,沒法使用單例,只能使用多例。
(3)通過實際測試,struts2速度慢,在於使用struts標籤,若是使用struts建議使用jstl。

3、項目源碼下載

連接:https://pan.baidu.com/s/1aHudrYYuMj1yIyBQJhPPPQ
提取碼:s8r1

4、參考文章

    1. http://yun.itheima.com/course/8.html
    2. https://blog.csdn.net/hbtj_1216/article/details/81102063
相關文章
相關標籤/搜索