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
相关文章
相关标签/搜索