注意:所有文章除特别说明外,转载请注明出处.
Spring MVC - FD
1.Spring MVC 中Controller层
SpringMVC中的Controller方法的参数可以是Integer,Double,自定义对象,ServletRequest,ServletResponse,ModelAndView等。
MVC控制层作用:
接收客户端的请求,然后调用Service层业务逻辑,获取到数据,传递给视图(客户端)用于视觉呈现
实现步骤:
1.在类上使用@Controller注解
作用: 告诉springmvc的dispatcherServlet这是一个Controller然后被dispatcherServlet的上下文所管理,并且完成它的依赖注入
2.在类上使用@RequestMapping注解 @RequestMapping 该注解可以用指定的URL路径访问本控制层
例如:@RequestMapping(“/user”)
作用: Controller负责处理的,根目录下的URL ,/user/** 下的所有路径都会被Controller所拦截
3.在方法上使用 @RequestMapping
例如:@RequestMapping(value = “login.do”, method = RequestMethod.POST)
作用:使该方法负责处理/user/login.do 这个url 并且是由post方法方法传递过来的请求
4.在方法的参数前绑定@RequestParam/@PathVariable/@Param注解
@RequestParam 根据参数名从URL中取得参数值
作用:负责把请求传入的参数,绑定到方法中的参数上,使方法中的参数值为请求传入的参数值
例如这条请求:/user/login.do?username=”admin” &password=”admin”
@Param 该注解的作用是作为Dao层的注解,作用是用于传递参数,一般参数在2-5个时使用最佳。
2.Spring MVC DispatchServlet
在整个Spring MVC框架中,DispatcherServlet 处于核心位置,它负责协调和组织不同组件完成请求处理并返回响应工作。
在看 DispatcherServlet 类之前,我们先来看一下请求处理的大致流程:
1.Tomcat服务器启动,对 DispatcherServlet 进行实例化,然后调用它的 init() 方法进行初始化。在这个初始化过程中完成了:
对 web.xml 中初始化参数的加载;建立 WebApplicationContext (SpringMVC的IOC容器),进行组件的初始化。
2.客户端发出请求,由 Tomcat 接收到这个请求,如果匹配 DispatcherServlet 在 web.xml 中配置的映射路径,Tomcat 就将请求转交给 DispatcherServlet 处理。
3.DispatcherServlet 从容器中取出所有 HandlerMapping 实例(每个实例对应一个 HandlerMapping 接口的实现类)并遍历,每个 HandlerMapping 会根据请求信息,通过自己实现类中的方式去找到处理该请求的 Handler (执行程序,如Controller中的方法),并且将这个 Handler 与一堆 HandlerInterceptor (拦截器) 封装成一个 HandlerExecutionChain 对象,一旦有一个 HandlerMapping 可以找到 Handler 则退出循环。
4.DispatcherServlet 取出 HandlerAdapter 组件,根据已经找到的 Handler,再从所有 HandlerAdapter 中找到可以处理该 Handler 的 HandlerAdapter 对象。
5.执行 HandlerExecutionChain 中所有拦截器的 preHandler() 方法,然后再利用 HandlerAdapter 执行 Handler ,执行完成得到 ModelAndView,再依次调用拦截器的 postHandler() 方法。
6.利用 ViewResolver 将 ModelAndView 或是 Exception(可解析成 ModelAndView)解析成 View,然后 View 会调用 render() 方法再根据 ModelAndView 中的数据渲染出页面。
7.最后再依次调用拦截器的 afterCompletion() 方法,这一次请求就结束了。
3.SpringMVC源码分析
SpringMVC中有两个重要的接口,HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler,在两个接口是在Spring3.1版本之后加入的。
3.1 SpringMVC处理请求的大致过程:
1.首先被DispatcherServlet截获,DispatcherServlet通过HandlerMapping获得HandlerExecutionChain,然后获得HandlerAdapter。
注意:前端控制器DispatcherServlet是整个SpringMVC的核心,负责统一分发所有请求,在web.xml中进行配置。
1.拦截符合特定格式的URL请求
拦截规则:
1. *.xxx,指定要拦截的特定类型,最简单实用的方式,并且不会拦截静态文件
2. /,使用REST风格进行拦截,但是会导致静态文件被拦截不能正常显示
3. /*,不能像Struts那样使用,会导致不能访问jsp
注意:如果使用/进行拦截,并且希望正常访问静态文件,可以在DispatcherServlet之前,使用DefaultServlet先拦截特定类型的请求(如:*.js、*.css等)。
2.初始化DispatcherServlet上下文对应的WebApplicationContext,并与业务层、持久化层建立联系
3.初始化SpringMVC的各个组件,并装配到DispatcherServlet中
2.HandlerMapping(处理器映射)
负责完成请求到控制器的映射。在servlet的配置文件中,进行uri与控制器的映射。同时,还可以对控制器进行拦截。
1.SpringMVC默认的处理器映射,直接将uri与实现类进行绑定,书写方便,但是耦合性高(使用BeanNameUrlHandlerMapping类)
2.使用SimpleUrlHandlerMapping,将uri与类的id进行绑定,彼此的耦合性低,更加灵活。
注意:对控制器进行声明,首先应该声明拦截器,然后利用SimpleUrlHandlerMapping映射拦截器与控制器。
3.控制器Controller
负责处理用户请求,完成之后返回ModelAndView对象给前端控制器。因为需要考虑并发,所以必须保证线程安全并且可重用。
注意:SpringMVC中的Controller与Struts中的Action基本相同。通过实现Controller接口或继承父类的方式编写控制器
实现步骤:
1.实现Controller接口
public class HelloController implements Controller {
// 相当于servlet的doGet和doPost方法
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
// 接收数据
// 调用服务层
return new ModelAndView("success","username","sean");
}
}
2.继承类的实现
1.继承AbstractController类,与接口类似需要重写里面的方法
2.继承MultiActionController类,可以实现多个方法,处理多个请求
public class MultiController extends MultiActionController {
// 自定义处理请求的方法
public ModelAndView insert(HttpServletRequest request,HttpServletResponse response) throws Exception {
return new ModelAndView("insertSuccess");
}
public ModelAndView update(HttpServletRequest request,HttpServletResponse response) throws Exception {
return new ModelAndView("updateSuccess");
}
}
注意:在把实现类编写之后需要配置相应的配置文件
3.继承AbstractCommandController类,用于获取页面的参数,将参数封装到指定的对象模型中。
4.HandlerAdapter在内部对于每个请求,都会实例化一个ServletInvocableHandlerMethod进行处理,ServletInvocableHandlerMethod在进行处理的时候,会分两部分别对请求跟响应进行处理。
5.然后HandlerAdapter得到ModelAndView,然后做相应的处理。
6.视图解析器ViewResolver
负责对ModelAndView对象的解析,并查找对应的View对象。SpringMVC框架默认通过转发进行页面跳转,如果想通过重定向的方式进行跳转(直接跳转:return "redirect:/index.jsp")。
注意:如果一个配置文件中出现多个视图解析器,可以通过设置order属性来设置优先级,值越低,优先级越高。
总结:1.在web.xml中配置
DispatcherServlet
核心控制器
2.在WEB-INF文件夹下创建springmvc-servlet.xml配置文件
3.学会@Controller
、@RequestMapping
、@RequestParam
以及@Model
域对象的使用
4.表单以post方式、get方式提交都是可以的
3.2 Spring MVC 的工作原理
1.将客户端请求提交给DispatcherServlet
2.根据<servlet-name>servlet.xml的配置,查找HandlerMapping
3.通过HandlerMapping找到处理请求的具体Controller
4.Controller调用业务逻辑处理
5.处理完成之后,返回ModelAndView对象给DispatcherServlet
6.通过ViewResolver找到负责显示的具体View
7.由View将结果渲染到客户端
4.SpringMVC重要注解(@ModelAttribute
)
该注解的作用是将请求参数绑定到Model对象。值得注意的是,该注解只支持一个属性value,类型为String,表示参数绑定的属性名称。而且此注解注释的方法在controller每个方法执行前都会执行。在 SpringMVC
的 Controller
中使用 @ModelAttribute
时,应用位置包括下面几种:
1.应用在方法上
注意:在被 @ModelAttribute 注解的方法会在Controller每个方法执行之前都执行,因此对于一个Controller中包含多个URL的时候,要谨慎使用。
1)使用 @ModelAttribute 注解无返回值的方法
@Controller
@RequestMapping("/modelattributeTest")
public class ModelAttributeTestController1 {
@ModelAttribute//使用ModelAttribute注解无返回值的方法
public void myModel(@RequestParam(required = false) String abc, Model model) {
model.addAttribute("attributeName", abc);
}
@RequestMapping(value = "/test1")
public String test1() {
return "modelattributetest/test1";
}
}
注意:最常用的方法是将上面的mymodel与test1合在一起使用,也是最常用的方法。
@RequestMapping(value = "/test2")
public String test1(@RequestParam(required = false) String abc, Model model) {
model.addAttribute("attributeName", abc);
return "modelattributetest/test1";
}
2)使用@ModelAttribute 注解带有返回值的方法
@ModelAttribute
public String myModel(@RequestParam(required = false) String abc) {
return abc;
}
@ModelAttribute
public Student myModel(@RequestParam(required = false) String abc) {
Student stu = new Student(abc);
return stu;
}
@ModelAttribute
public int myModel(@RequestParam(required = false) int number) {
return number;
}
上面的三种情况等同于
model.addAttribute("string", abc);
model.addAttribute("int", number);
model.addAttribute("student", stu);
自定义,给@ModelAttribute添加value属性
@ModelAttribute(value = "num")
public int myModel(@RequestParam(required = false) int number) {
return number;
}
相当于:model.addAttribute(“num”, number);
2.应用在方法的参数上(使用@ModelAttribute注解方法的参数)
@Controller
@RequestMapping("/modelattributeTest3")
public class ModelAttributeTestController3 {
@ModelAttribute(value = "attributeName")
public String myModel(@RequestParam(required = false) String abc) {
return abc;
}
@ModelAttribute
public void myModel3(Model model) {
model.addAttribute("name", "SHANHY");
model.addAttribute("age", "28");
}
@RequestMapping(value = "/test1")
public String test1(@ModelAttribute("attributeName") String str,
@ModelAttribute("name") String str2,
@ModelAttribute("age") String str3) {
return "modelattributetest/test1";
}
}
注意:从上面的程序中可以看出,使用@ModelAttribute注解的参数,表示从前面的Model中提取对应名称的属性
3.应用在方法上,并且方法也使用了@RequestMapping
@Controller
@RequestMapping("/modelattributeTest4")
public class ModelAttributeTestController4 {
@RequestMapping(value = "/test1")
@ModelAttribute("name")
public String test1(@RequestParam(required = false) String name) {
return name;
}
}
注意:这种情况下,返回值String(或者其他对象,就不再是视图。还是我们上面将到的放入 Model 中的值,此时对应的页面就是 @RequestMapping的值 test1。
总结:@Controller 相当于创建了一个bean对象
@RequestMapping(value=”..”) 就是一个请求映射,返回值return返回一个页面(前缀+逻辑视图+后缀)
4.1 Spring MVC 的常用注解
@Controller:声明Action组件,负责注册bean到Spring上下文
@RequestMapping:用于为控制器指定可以处理的url请求(Springmvc页面向controller传递参数的方式)
@RequestParam:用于指定参数的name属性(Springmvc页面(ftl)向controller层传递参数的方式)
@RequestBody:用于读取Request请求的body部分数据
解释:
1. @requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等。一般情况下来说常用其来处理application/json类型。
2. 通过@RequestBody可以将请求体中的JSON字符串绑定到相应的bean上,也可以将其绑定到对应的字符串上。
3. @RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为JSON、XML等格式的数据并绑定到Controller方法的参数上。
4. 最新解释:该注解将@Controller中方法的返回对象,根据request中头部(header)的accept的内容通过适当的转换,转换为指定的格式后输出到response对象。
5. 使用时机:返回数据不是HTML标签页,是其他格式数据(如:JSON/XML等)。
@ResponseBody:用于将控制器方法返回的对象写入到Response对象的body数据区
解释:
1. 将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或XML数据。
2. @ResponseBody注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据(JSON/XML)通过response响应给客户端。
3. @ResponseBody注解可被应用于方法上,标志该方法的返回值应该被直接写回到HTTP响应体中去(不会被放置到Model中或解释为一个视图名)。在实际开发中,返回JSON是最常见的一种方式。
原理:当一个处理请求的方法被标记为@ResponseBody时,就说明该方法需要输出其他视图(JSON/XML),Spring MVC通过已经定义的转化器做转化输出,默认输出JSON。
注意:在使用此注解之后不会再走视图处理器(ViewResolver)是直接将数据写入到输入流中,等同于通过response对象输出指定格式的数据。
注意:@RequestBody是写在方法参数前,作用于方法参数。@ResponseBody是写在方法上,作用于方法返回值。 因为采用的是JSON格式进行数据交互。
重要:使用
@ResponseBody
注解,返回值直接作为http响应的内容的响应体部分发送给客户端,可以让我们将想要返回的内容直接返回给客户端。
@PathVariable:用于指定url作为参数 用来获得请求URL中的动态参数的,将请求URL的模板变量映射到功能处理方法的参数上。
@Resource:用于注入( 由J2EE提供 ) 默认按名称装配
@Autowired :用于注入(由spring提供) 默认按类型装配
@ExceptionHandler:用于异常处理的方法
@ControllerAdvice:用于使控制器成为全局的异常处理类
@ModelAttribute:用于优先调用被注解的方法,或注解参数中的隐藏对象
@JsonFormat:用于将后台返回前台的Date变量转换为字符串类型,还可以实现前台到后台的类型转换(注:@JsonFormat注解的作用就是完成JSON字符串到Java对象的转换工作,与参数传递方向无关)
@DateTimeFormat:用于将前台传递到后台字符串变量转换成Date类型
扩展:
@RequestMapping 注解的六个属性
1.value/method
value:指定请求的实际地址
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中必须包含某些指定的headers值,才让该方法处理请求
@Deprecated、@Override、@SuppressWarnings这三个注解的@Retention注解的属性值分别是:
4.3 ViewResolver接口实现类
InternalResourceViewResolver类(加入JSTL支持)
4.4 springmvc.xml配置文件
<!--在最开始应该引入springmvc的约束文件-->
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 配置databaseSource-->
<!-- ================== 方式1 ==================== -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/storemanager?characterEncoding=utf-8"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
<!-- 连接池初始化连接个数 -->
<property name="initialSize" value="3" />
<!-- 连接池的最大值 -->
<property name="maxActive" value="10" />
<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
<property name="maxIdle" value="5" />
<!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
<property name="minIdle" value="2" />
<!-- 获取连接最大等待时间 -->
<!-- <property name="maxWait" value="60000" /> -->
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="25200000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<!-- <property name="filters" value="mergeStat" /> -->
<!-- <property name="filters" value="stat" /> -->
</bean>
<!-- ====================== 方式2 ========================== -->
<!-- 2.创建数据源 添加连接池则改变数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
<!-- 配置sessionFactory,用于获取session -->
<!-- ====================================== -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="mappingResources">
<list>
<value>com/kl/napchen/store/bean/User.hbm.xml</value>
<value>com/kl/napchen/store/bean/ProductIn.hbm.xml</value>
<value>com/kl/napchen/store/bean/ProductOut.hbm.xml</value>
<value>com/kl/napchen/store/bean/ProductType.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQL5Dialect
</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="current_session_context_class">thread</prop>
</props>
</property>
<!-- 自动扫描注解方式配置的hibernate类文件 -->
<!-- <property name="packagesToScan"> -->
<!-- <list> -->
<!-- <value>light.mvc.model</value> -->
<!-- </list> -->
<!-- </property> -->
</bean>
<!-- 配置事务管理器 -->
<!-- ====================================== -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<!-- <property name="rollbackOnCommitFailure" value="true" /> -->
</bean>
<!-- 注解方式配置事物 -->
<!-- ====================================== -->
<!-- <tx:annotation-driven transaction-manager="transactionManager" /> -->
<!-- AOP方式配置事物 -->
<!-- ====================================== -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- <tx:method name="get*" propagation="REQUIRED" read-only="true" /> -->
<!-- <tx:method name="add*" propagation="REQUIRED" /> -->
<tx:method name="delete" propagation="REQUIRED" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="transactionPointcut"
expression="execution(* com.kl.napchen.store.impl..*.*(..))" />
<aop:advisor pointcut-ref="transactionPointcut"
advice-ref="transactionAdvice" />
</aop:config>
<!-- 启用aspectj注解自动代理 -->
<!-- ====================================== -->
<aop:aspectj-autoproxy />
<!-- 配置代理bean -->
<!-- ====================================== -->
<bean id="adviceLog" class="com.kl.napchen.store.annotation.AdviceLog"></bean>
<bean id="adviceUserLog" class="com.kl.napchen.store.annotation.AdviceUserLog"></bean>
<!-- 配置Bean -->
<!-- ====================================== -->
<bean id="user" class="com.kl.napchen.store.bean.User"></bean>
<bean id="productIn" class="com.kl.napchen.store.bean.ProductIn"></bean>
<bean id="productOut" class="com.kl.napchen.store.bean.ProductOut"></bean>
<bean id="productType" class="com.kl.napchen.store.bean.ProductType"></bean>
<bean id="sessionInfo" class="com.kl.napchen.store.global.SessionInfo"></bean>
<bean id="pageGrid" class="com.kl.napchen.store.page.PageGrid"></bean>
<!-- 配置操作数据的Dao -->
<!-- ====================================== -->
<bean id="userDao" class="com.kl.napchen.store.dao.UserDao"></bean>
<bean id="productInDao" class="com.kl.napchen.store.dao.ProductInDao"></bean>
<bean id="productOutDao" class="com.kl.napchen.store.dao.ProductOutDao"></bean>
<bean id="productTypeDao" class="com.kl.napchen.store.dao.ProductTypeDao"></bean>
<!-- 配置业务处理的service -->
<!-- ====================================== -->
<bean id="userImpl" class="com.kl.napchen.store.impl.UserImpl"></bean>
<bean id="productInImpl" class="com.kl.napchen.store.impl.ProductInImpl"></bean>
<bean id="productOutImpl" class="com.kl.napchen.store.impl.ProductOutImpl"></bean>
<bean id="productTypeImpl" class="com.kl.napchen.store.impl.ProductTypeImpl"></bean>
<!-- 配置控制流程的controller -->
<!-- ====================================== -->
<!-- <bean id="userController" class="com.kl.napchen.store.controller.UserController"></bean> -->
<!-- <bean id="productInController" class="com.kl.napchen.store.controller.ProductInController"></bean> -->
<!-- <bean id="productOutController" class="com.kl.napchen.store.controller.ProductOutController"></bean> -->
<!-- <bean id="productTypeController" class="com.kl.napchen.store.controller.ProductTypeController"></bean> -->
<!-- 配置获取spring容器中Bean的工具Bean -->
<!-- 由于持有ApplicationContext, -->
<!-- 可以使用SpringContextHolder.getBean('xx')的静态方法得到spring bean对象 -->
<!-- ====================================== -->
<!-- <bean class="com.kl.napchen.storeManagerSystem.contextHolder.SpringContextHolder"
lazy-init="false" /> -->
<!-- 对静态资源文件的访问 方案一 (二选一) -->
<!-- 使用"*.do"配置DispatcherServlet时不存在静态资源访问问题 ,拦截器将不会拦截静态资源的URL -->
<!-- 使用"/"配置DispatcherServlet时存在静态资源访问问题,采用以下两种方案解决 -->
<!-- ====================================== -->
<mvc:default-servlet-handler />
<!-- 对静态资源文件的访问 方案二 (二选一) -->
<!-- ====================================== -->
<!-- 静态资源映射 -->
<!-- <mvc:resources mapping="/js/**" location="/WEB-INF/js/" /> -->
<!-- <mvc:resources mapping="/css/**" location="/WEB-INF/css/" /> -->
<!-- <mvc:resources mapping="/fonts/**" location="/WEB-INF/fonts/" /> -->
<!-- <mvc:resources mapping="/plugins/**" location="/WEB-INF/plugins/" /> -->
<!-- <mvc:resources mapping="images/**" location="/WEB-INF/images/" /> -->
<!-- 默认的注解映射的支持 -->
<!-- 采用这下面种方式将自动装配DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter -->
<!-- 采用这下面种方式将无法在 DefaultAnnotationHandlerMapping配置拦截器 -->
<!-- ====================================== -->
<mvc:annotation-driven />
<!-- 配置 DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter -->
<!-- ====================================== -->
<!-- <bean -->
<!-- class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"> -->
<!-- 配置拦截器 -->
<!-- <property name="interceptors"> -->
<!-- <list> -->
<!-- <bean class="com/kl/napchen/storeManagerSystem/interceptor/MyInterceptor"></bean> -->
<!-- </list> -->
<!-- </property> -->
<!-- </bean> -->
<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
</bean> -->
<!-- 隐式地向 Spring容器注册这4个BeanPostProcessor -->
<!-- AutowiredAnnotationBeanPostProcessor、 -->
<!-- RequiredAnnotationBeanPostProcessor、 -->
<!-- CommonAnnotationBeanPostProcessor、 -->
<!-- PersistenceAnnotationBeanPostProcessor -->
<!-- ====================================== -->
<!-- <context:annotation-config /> -->
<!-- 设置使用注解的类所在的jar包 ,使用这种即可省去上面的声明 -->
<!-- ====================================== -->
<context:component-scan base-package="com.kl.napchen.store.controller" />
<context:component-scan base-package="com.kl.napchen.store.impl" />
<context:component-scan base-package="com.kl.napchen.store.baseService" />
<!-- 映射“/”的url -->
<!-- ====================================== -->
<!-- <mvc:view-controller path="/" view-name="forward:/index2" /> -->
<!-- configure the InternalResourceViewResolver -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"
/> -->
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 自定义拦截器 (近似-总拦截器) -->
<!-- ====================================== -->
<mvc:interceptors>
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
<bean class="com.kl.napchen.store.interceptor.MyInterceptor" />
</mvc:interceptors>
<!-- 总错误处理 -->
<!-- ====================================== -->
<bean id="exceptionResolver"
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 配置不同类别的错误对应的view和状态码 -->
<property name="exceptionMappings">
<props>
<prop key="java.lang.Exception">errors/error</prop>
<prop key="java.lang.Throwable">errors/error</prop>
<!-- 上传文件大于最大尺寸后转向出错页面 -->
<!-- ====================================== -->
<prop
key="org.springframework.web.multipart.MaxUploadSizeExceededException">errors/uploadError
</prop>
</props>
</property>
<property name="statusCodes">
<props>
<prop key="errors/error">500</prop>
<prop key="errors/404">404</prop>
</props>
</property>
<!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 -->
<property name="warnLogCategory">
<value>org.springframework.web.servlet.handler.SimpleMappingExceptionResolver
</value>
</property>
<!-- 默认错误页面,当找不到上面mappings中指定的异常对应视图时,使用本默认配置 -->
<property name="defaultErrorView" value="errors/error"></property>
<!-- 默认HTTP状态码 -->
<property name="defaultStatusCode" value="500"></property>
</bean>
</beans>
5.Spring MVC向页面传送参数的四种方式
1.使用HttpServletRequest
和Session
,然后setAttribute()
(与Servlet一样) request.setAttribute("user",user_data);
。
2.使用ModelAndView
对象
@RequestMapping("/login.do")
public ModelAndView login(String name,String pass){
User user = userService.login(name,pwd);
Map<String,Object> data = new HashMap<String,Object>();
data.put("user",user);
return newModelAndView("success",data);
}
3.使用ModelMap
对象 ModelMap
数据会利用HttpServletRequest
的Attribute
传值到success.jsp
中。
@RequestMapping("/login.do")
public String login(String name,String pass ,ModelMap modelMap){
User user = userService.login(name,pwd);//调用service层的login方法
modelMap.addAttribute("user",user);
modelMap.put("name",name);
return "success";
}
4.使用@ModelAttribute
注解 @ModelAttribute
数据会利用HttpServletRequest
的Attribute
传值到success.jsp
中。
@RequestMapping("/login.do")
public String login(@ModelAttribute("user") User user) {
return "success";
}
@ModelAttribute("name")
public String getName(){
return name;
}
注意:Spring MVC默认是采用转发来定位视图,如果要使用定向来转发视图,可以使用redirect前缀。
public String login(){
return "redirect:registe.do";
}
6.Spring MVC 的执行流程
1.(前端)控制层(Controller):接收请求、转发请求
2.(后端)控制层(Controller):struts(action):接受请求、处理请求数据
注意:
Spring MVC
就是Spring
,所以其约束
与Spring的约束
一致。查找方法:
SpringMVC约束的查找是在..\jar\spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\xsd-config.html路径下查找然后复制粘贴。
3.程序实现流程
1.配置默认处理器映射器(BeanNameUrlHandlerMapping):映射器会将请求映射到Controller(根据bean(自定义Controller)的name属性的url去寻找执行类Controller)
2.配置默认处理器适配器(SimpleUrlHandlerMapping):负责执行UserController(依赖自定义的控制器bean,表示多个*.do文件可以访问一个或多个Controller)
3.配置ControllerClassNameHandlerMapping:这个Mapping配置之后我们便能够使用Controller的【类名.do】来访问这个Controller
4.SimpleControllerHandlerAdapter
4.代码层面的实现流程
1.配置web.xml(配置前端控制器:DispatcherServlet)
2.配置springmvc.xml
1.配置处理器映射器(默认:BeanNameUrlHandlerMapping:根据自定义Controller的name属性的URL去寻找Handler(相当于Struts2中的Action))
2.配置处理器适配器执行Controller(默认:SimpleControllerHandlerAdapter(执行Controller))
3.配置自定义的Controller
4.配置SpringMVC视图解析器:解析逻辑视图 后台返回逻辑视图(视图解析器解析出真正的物理视图:前缀+逻辑视图+后缀===/WEB-INF/jsps/index.jsp)
3.自定义Controller(UserController implements Controller)
4.配置自定义的Controller的bean(在springmvc.xml配置文件中配置Controller,表示这个对象交给Spring来创建)
<bean name="/hello.do" class="cn.itcast.controller.UserController"></bean>(在bean中定义的name属性就是URL访问地址)
5.配置视图解析器(如果Controller使用逻辑视图,必须配置视图解析器)
6.访问 项目名+自定义的Controller的name属性URL
http://localhost:8080/springmvc/hello.do
Struts2与SpringMVC的区别
1.实现机制
Struts2底层是过滤器,是基于过滤器实现
SpringMVC是基于Servlet实现的
2.执行速度
Struts2是多列的,而SpringMVC是单列的,执行速度快。
3.参数封装
Struts2参数封装是基于属性封装
SpringMVC是基于方法封装的,颗粒更细
Spring MVC - SD
Spring MVC 的页面参数回显
SpringMVC
使用Model
对象,Model
对象相当于application
(注意:application对象中数据可以是EL表达式进行获取)。
1.JSON数据交互
输入json串,输出是json串和输入key/value,输出是json串两种情况下的交互。
1.添加JSON转换的依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
2.配置JSON转换器(在注解适配器中加入messageConverters)
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
注意:如果使用mvc:annnotation-driven/注解便不需要上面的配置。
3.交互测试
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>json交互测试</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
//请求json,输出是json
function requestJson(){ 省略 }
//请求key/value,输出是json
function responseJson(){ 省略 }
</script>
</head>
<body>
<input type="button" onclick="requestJson()" value="请求json,输出是json"/>
<input type="button" onclick="responseJson()" value="请求key/value,输出是json"/>
</body>
4.Controller
//请求json串(商品信息),输出json(商品信息)
//@RequestBody将请求的商品信息的json串转成itemsCustom对象
//@ResponseBody将itemsCustom转成json输出
@RequestMapping("/requestJson")
public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom){
//@ResponseBody将itemsCustom转成json输出
return itemsCustom;
}
5.输入json串,输出json串
//使用jQuery的ajax方法提交json串,对输出的json结果进行解析
//jsp页面
//请求json,输出json
function requesetJson(){
$.ajax({
type:'post',
url:'${pageContext.request.contextPath}/requestJson.action',
contentType:'application/json;charset=utf-8',
//数据格式是json串
data:'{"name":"手机","price":"255"}',
success:function(data){
//操作成功返回结果
alert(data);
}
});
}
6.输入key/value,输出是JSON串
//请求key/value,输出是json
function responseJson(){
$.ajax({
type:'post',
url:'${pageContext.request.contextPath }/responseJson.action',
//请求是key/value这里不需要指定contentType,因为默认就 是key/value类型
//contentType:'application/json;charset=utf-8',
//数据格式是json串,商品信息
data:'name=手机&price=999',
success:function(data){//返回json结果
alert(data.name);
}
});
}
7.Controller
/请求key/value,输出json
@RequestMapping("/responseJson")
public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom){
//@ResponseBody将itemsCustom转成json输出
return itemsCustom;
}
2.数据回显
1.POJO数据回显方法(springmvc 默认对POJO对象进行回显)
POJO数据传入Controller方法之后,springmvc自动将POJO数据放到request域,key等于POJO类型。使用@ModelAttribute
指定POJO回显页面在request中的key。
2.@ModelAttribute将返回值传到页面
// 商品分类
// itemtypes表示最终将方法返回值放在request中的key
@ModelAttribute("itemtypes")
public Map<String, String> getItemTypes() {
Map<String, String> itemTypes = new HashMap<String, String>();
itemTypes.put("101", "数码");
itemTypes.put("102", "母婴");
return itemTypes;
}
//页面上获得itemTypes数据
<td>
商品名称:<input name="itemsCustom.name" />
商品类型:
<select name="itemtype">
<c:forEach items="${itemtypes}" var="itemtype">
<option value="${itemtype.key }">${itemtype.value }</option>
</c:forEach>
</select>
</td>
3.简单类型数据回显
//这里使用最简单的方法:model
model.addAttribute("id",id);//参数回显
Spring MVC 的URL模板映射
主要是为请求restfull
(软件架构设计模式,请求更简洁、更安全,方便于搜索引擎收录)设计模式
扩展:如果一个架构符合REST原则,就称它为RESTful架构。REST:表现层状态转化
SpringMVC开发中Model的解释
在SpringMVC
开发中,Model
是一种概念,而不是一种具体的参数或者是其他的具体的体现,MVC
是软件工程中一种常见的规范的设计模式(model(模型层) view(视图层) Controller(控制层))
1.Model(模型)包括:数据模型(POJO或Bean之类的东西)和业务逻辑(登录、注册操作等),是用来从后台封装数据到页面的(后台定的实体类)。
注意:POJO是一个域对象,用来接收并封装前台页面传递过来的数据。
2.Controller(控制):使得Model层能在View层表示出来
SpringMVC的model
1.springmvc接收参数的时候可以自动注入model
或者modelAndView
这两个类
@RequestMapping("/aa")
public String aa(Model model) {
model.addAttribute("key","value");
return "HH";
}
2.然后在页面中,这些value可以通过key取出来。这便就是简化了的springmvc
的工作过程。
3..RequestMapping
注意:根路径就是用来隔离Controller里面的相同的方法
4.SpringMVC封装参数
注意:SpringMVC没有成员变量,将需要传递参数对象放入方法中,当请求这个方法的时候,这个方法里面对象会被自动创建,需要封装的参数自动被封装到方法的对象中。
Spring MVC 的转发与重定向(springmvc forward/redirect)
语法:
1.return "forward:/index.do";//forward在跳转后可以去到值 forward跳转后地址栏URL不会改变
2.return "redirect:/register.do";//redirect在跳转后无法取到值 redirect跳转后地址栏URL会改变
spring mvc 的配置文件内容
<mvc:annotation-driven/>
:默认创建多个对象 RequestMappingHandlerMapping
(处理器映射器)/RequestMappingHandlerAdapter
(处理器适配器),默认提供json
数据格式的支持。
注意:以后在创建SpringMVC处理器映射器与适配器的时候可以直接使用
<mvc:annnotation-driven/>
作创建springMVC
相关的操作。注意:
JavaBean
不能添加@XmlRootElement
(这个只提供对xml的视图支持)
注解@RequestBody、@ResponseBody
1.@RequestBody作用:把前台页面传送json格式数据强制转换为JavaBean,可以将请求体中的JSON字符串绑定到响应的Bean上,也可以将其绑定在对应的字符串上面。
2.@ResponseBody作用:在后台将JavaBean转换成json格式的数据返回页面,是将Controller的方法返回的对象通过适当的转换器转换成指定的格式之后,写入到response对象的body区。
注意:这两个注解不能直接使用,需要依赖于JACKson的jar包。
开发实现步骤:
1.导入jar包
Jackson-core-asl-1.9.11.jar
Jackson-mapper-asl-1.9.11.jar
2.配置json格式转换
<property name="messageConverters">
<bean class="MappingJacksonHttpMessageConverter.class">
</property>
浅谈 @RequestMapping
@ResponseBody
和 @RequestBody
注解的用法与区别
1.@RequestMapping
@RequestMapping是用来处理请求地址映射的注解,可用于类或方法上。
用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径;
用于方法上,表示在类的父路径下追加方法上注解中的地址将会访问到该方法,此处需注意@RequestMapping用在类上可以没用,但是用在方法上必须有。
例:原理也非常好了解,其对应的 action 就是“ (父路径) controller/(父路径下方法路经)method ”
在类上注释的是@RequestMapping(value = "/Controllers")
在方法上注释的是 @RequestMapping(value = "/method")
注意: @PathVariable 注解,其用来获取请求路径(url)中的动态参数。
2.@ResponseBody
@ResponseBody注解表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。
作用:该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConvert转换为指定的格式后,写入到Response对象的body数据区
注意:异步获取json数据,加上@Responsebody注解后,就会直接返回json数据
3.@RequestBody
@RequestBody注解则是将 HTTP 请求正文插入方法中,使用适合的 HttpMessageConverter 将请求体写入某个对象。
作用:
1) 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上。
2) 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
@ResponseBody(将后台pojo转换成json对象,返回到页面)
@RequestBody(接收前台json数据,将json数据自动封装到JavaBean)
上面两者的开发实现步骤:
1.导入jar包(Jackson-core-asl-1.9.11.jar Jackson-mapper-asl-1.9.11.jar)
2.修改springmvc.xml文件
1.在springmvc.xml文件中的处理器适配器下配置我们的json转换对象(messageConverters)
<bean class="RequestMappingHandlerAdapter.class这个类">
<property name="messageConverters">
<bean class="MappingJacksonHttpMessageConverter这个类"></bean>//要转换的json格式的类数据
</bean>
3.页面传递json格式数据
1.使用ajax传递json格式数据
4.自定义Controller类里面(后台)
//1.请求json格式数据,返回json
@RequestMapping("requestJson")
public @ResponseBody(转换为json格式) User requestJson(@RequestBody(封装在user对象里面) User user){
System.out.println(user);//测试user对象输出的值是否正确
return user;
}
//2.跳转到RequestJson页面
@RequestMapping("toJson")
public String toJson(){
return "requestJson";
}
5.toJson.do(前台)
1.首先引入在JSP页面引入js
function requestJson(){
//模拟json格式数据
var jsonObj = JSON.stringify({"username":"张三","sex":"男","address":"东北那嘎达"});
$.ajax({
type:'POST',
url:'/springmvc19_day01_02/user/requestJson.do',
contentType:'qpplication/json;charset=utf-8',
data:jsonObj,
success:function(data){
alert(data);
}
})
}
另:请求Pojo,返回json
SpringMVC多视图
开发步骤:
1.导入xml格式支持的jar包
spring-oxm-3.2.0.RELEASE.jar
2.配置springmvc.xml文件支持多视图
<bean class="ContentNegotiatingViewResolver这个对象的类">
//配置支持的媒体类型
<property name="contentNegotiationManager">
<bean class="ContentNegotiationManagerFactory这个对象的类"></bean>
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"></entry>
<entry key="xml" value="application/xml"></entry>
</map>
</property>
//指定默认视图
<property name="defaultViews">
//支持多个视图
<list>
//对json格式视图支持
<bean class="MappingJacksonJsonView这个类的URL"></bean>
//对xml格式视图的支持
<bean class="MarshallingView这个类的URL">
<constructor-arg>
<bean class="Jaxb2Marshaller这个类URL">
<property name="classesToBeBound">
<list>
<value> ... </value>
</list>
</property>
</bean>
</constructor-arg>
</list>
</property>
</bean>
3.编写自定义UserController类
@RequestMapping("multiView")
public User multiView(){
User user = new User();
user1.setId(1);
user1.setSex("男");
user1.setUsername("张三丰");
user1.setAddress("武当山");
user1.setBirthday(new Date());
return user1;
}
4.访问
约定rest目录下的所有以json和xml扩展名都支持相应的视图
SSM整合
开发步骤:
1.导入jar包(导入spring(包含springMVC)/mybatis/mybatis-spring整合)数据库驱动、JSTL、c3p0管理数据源、log4j。
2.配置web.xml文件
后续添加…………….
Spring MVC 的页面缓存
使用Oscache实现页面缓存
测试页面缓存
实现步骤:
1.导入相关jar包
关于Controller里面的方法中的参数问题
1.Model model
model主要是用来传值的,与request、session的作用效果差不多
model的作用跟request的setAttribute(arg0,arg1)是一样的,都是把值或是对象进行一个保存,然后可以在视图上进行取值,同样都可以使用ognl表达式取值。
springmvc使用model的原因:
request只是一个请求,作用就是从客户端发起一个请求,并且携带客户端发起的这个请求所带的参数,在业务层中进行参数的获取并且做出相对应的处理,到这里这个request请求对象的工作就应该结束了,剩下的就是客户端对这个请求和参数做出处理结果并且生成响应response返回客户端。所以不应该用request进行存值,来达到模型层和视图层的一个连接,所以才使用model或是modelandview这个专门的对象来进行模型层的存在和视图层的取值model会在模型层进行存值,在视图层中,他会去检查model对象中是否用这个属性,有ta就会渲染出来,request请求结束后就会自动清除model的数据。
扩展:
1.JSTL中<c:forEach>标签:forEach标签作用是做一个循环遍历使用
2.model.addAttribute()的作用:往前台传数据,可以传对象,可以传List,通过el表达式 ${}可以获取到,类似于request.setAttribute("sts",sts)效果一样
3.@ModelAttribute 用法:1.直接标记在方法上 2.标记在方法的参数上
4.@RequestParam(value="xxx" required=false) 1.可以对传入参数指定参数名
5.可以通过required=false/true来要求@RequestParam配置的前端参数是否一定要传
6.如果@RequestParam注解的参数是int类型,并且required=false,此时如果不传参数的话会报错。
第11章 为Spring添加REST功能
简洁的说REST
就是将资源的状态以合适的形式从服务器端转移到客户端<或者反之>。Spring 3
对Spring MVC
的一些增强功能为REST
提供了良好的支持。现在,Spring支持以下方式开发REST资源。
1.控制器可以处理所有的HTTP方法,包括:get、put、delete和post方法
2.新的@PathVariable注解使得控制器能够处理参数化的URL(将变量输入作为URL的一部分)
3.Spring的表单绑定JSP标签库<form:form>标签以及新的HiddenHttpMethodFilter,使得通过HTML表单提交put和delete请求成为可能。
4.通过使用Spring的视图和视图解析器,资源可以以各种形式进行表述,包括将模型数据表现为:XML/JSON/ATOM/RSS的新视图实现。
Spring MVC - TD
1.MVC概要
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范,用一种将业务逻辑、数据、显示分离的方法组织代码。MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异
注意:在WEB开发的早期,通常采用的是Model1(JSP兼顾View和Controller两种角色),主要分为两层,视图层与模型层。而model2将项目分成三个部分,包括视图、控制、模型。
2.控制器定义与@RequestMapping详解
控制器:提供访问应用程序的行为,通常通过服务接口定义或注解定义两种方式,控制器解析用户的请求并将其转换为一个模型。
小结:实现接口Controller定义控制器是较老的办法,缺点是:一个控制器中只有一个Action,如果要多个Action则需要定义多个Controller。定义的方式比较麻烦。Spring 2.5以后采用注解的方式定义解决这些问题。
注意:Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。
@RequestMapping注释用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
路径变量占位、URI模板模式
在SpringMVC中可是使用@PathVariable注释方法参数的值绑定到URI模板变量
优点:使得路径名变得更加简洁,获得参数更加方便,框架会自动进行类型转换。
3.请求处理方法Action详解
1.Action参数类型
@ModelAttribute模型特性
@ModelAttribute可以应用在方法参数上或方法上,他的作用主要是当注解在方法中时会将注解的参数对象添加到Model中;
当注解在请求处理方法Action上时会将该方法变成一个非请求处理的方法,但其它Action被调用时会首先调用该方法。
注意:boolean类型的值生成的get/set属性名称前是不带get与set的,这样会引起异常,建议手动修改。
SpringMVC验证器Validator
SpringMVC验证器Validator是一个接口,通过实现该接口来定义对实体对象的验证。
1.验证器接口
package org.springframework.validation;
/**
* Spring MVC内置的验证器接口
*/
public interface Validator {
/**
* 是否可以验证该类型
*/
boolean supports(Class<?> clazz);
/**
* 执行验证 target表示要验证的对象 error表示错误信息
*/
void validate(Object target, Errors errors);
}
2.定义验证器(实现该接口)
package com.zhangguo.springmvc51.entities;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
/**
* 产品验证器
*
*/
public class ProductValidator implements Validator {
//当前验证器可以验证的类型,重写接口中的方法
@Override
public boolean supports(Class<?> clazz) {
return Product.class.isAssignableFrom(clazz);
}
//执行校验,重写接口中的方法
@Override
public void validate(Object target, Errors errors) {
//将要验证的对象转换成Product类型
Product entity=(Product)target;
//如果产品名称为空或为空格,使用工具类
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required", "产品名称必须填写");
//价格,手动判断
if(entity.getPrice()<0){
errors.rejectValue("price", "product.price.gtZero", "产品价格必须大于等于0");
}
//产品类型必须选择
if(entity.getProductType().getId()==0){
errors.rejectValue("productType.id", "product.productType.id.required", "请选择产品类型");
}
}
}
注意:ValidationUtils是一个工具类,中间有一些方法可以用于判断内容是否有误。
3.执行校验
// 新增保存,如果新增成功转回列表页,如果失败回新增页,保持页面数据
@RequestMapping("/addSave")
public String addSave(Model model, Product product, BindingResult bindingResult) {
// 创建一个产品验证器
ProductValidator validator = new ProductValidator();
// 执行验证,将验证的结果给bindingResult,该类型继承Errors
validator.validate(product, bindingResult);
// 获得所有的字段错误信息,非必要
for (FieldError fielderror : bindingResult.getFieldErrors()) {
System.out.println(fielderror.getField() + "," + fielderror.getCode() + "," + fielderror.getDefaultMessage());
}
// 是否存在错误,如果没有,执行添加
if (!bindingResult.hasErrors()) {
// 根据类型的编号获得类型对象
product.setProductType(productTypeService.getProductTypeById(product.getProductType().getId()));
productService.addProduct(product);
return "redirect:/";
} else {
// 与form绑定的模型
model.addAttribute("product", product);
// 用于生成下拉列表
model.addAttribute("productTypes", productTypeService.getAllProductTypes());
return "product/add";
}
}
注意:在参数中增加了一个BindingResult类型的对象,该类型继承自Errors,获得绑定结果,承载错误信息,该对象中有一些方法可以获得完整的错误信息,可以使用hasErrors方法判断是否产生了错误。
4.在UI中添加错误标签
add.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<link href="styles/main.css" type="text/css" rel="stylesheet" />
<title>新增产品</title>
</head>
<body>
<div class="main">
<h2 class="title"><span>新增产品</span></h2>
<form:form action="addSave" modelAttribute="product">
<fieldset>
<legend>产品</legend>
<p>
<label for="name">产品名称:</label>
<form:input path="name"/>
<form:errors path="name" cssClass="error"></form:errors>
</p>
<p>
<label for="title">产品类型:</label>
<form:select path="productType.id">
<form:option value="0">--请选择--</form:option>
<form:options items="${productTypes}" itemLabel="name" itemValue="id"/>
</form:select>
<form:errors path="productType.id" cssClass="error"></form:errors>
</p>
<p>
<label for="price">产品价格:</label>
<form:input path="price"/>
<form:errors path="price" cssClass="error"></form:errors>
</p>
<p>
<input type="submit" value="保存" class="btn out">
</p>
</fieldset>
</form:form>
<p style="color: red">${message}</p>
<p>
<a href="<c:url value="/" />" class="abtn out">返回列表</a>
</p>
</div>
</body>
</html>
JSR303验证器
JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。
JSR 303 – Bean Validation 是一个数据验证的规范。JSR303只是一个标准,是一验证规范,对这个标准的实现有:hibernate-validator,Apache BVal等。这里我们使用hibernate-validator实现校验。
使用jQuery扩展插件Validate实现前端校验
jquery.validate是基于jQuery的一个B/S客户端验证插件,借助jQuery的优势,我们可以迅速验证一些常见的输入,大大提高了开发效率
3.1、jQuery扩展插件validate—1基本使用方法 http://www.cnblogs.com/best/archive/2011/09/05/2167723.html
3.2、jQuery扩展插件validate—2通过参数设置验证规则 http://www.cnblogs.com/best/archive/2011/09/05/2167733.html
3.3、jQuery扩展插件validate—3通过参数设置错误信息 http://www.cnblogs.com/best/archive/2011/09/05/2167742.html
3.4、jQuery扩展插件validate—4设置错误提示的样式 http://www.cnblogs.com/best/archive/2011/09/05/2167756.html
3.5、jQuery扩展插件validate—5添加自定义验证方法 http://www.cnblogs.com/best/archive/2011/09/05/2167773.html
3.6、jQuery扩展插件validate—6radio、checkbox、select的验证 http://www.cnblogs.com/best/archive/2011/09/05/2167779.html
注意:validate只是使验证变得方便,简单,本质还是使用js,不论多么强大的js验证,当用户把js禁用或使用机器直接发起请求时都不能确保数据的完整性,所有不要把希望寄托在客户端验证,个人认为每一个客户端验证都要服务器进行再次验证。
Spring MVC 的文件上传
在Spring MVC中有两种实现上传文件的办法,第一种是Servlet3.0以下的版本通过commons-fileupload与commons-io完成的通用上传,第二种是Servlet3.0以上的版本的Spring内置标准上传,不需借助第3方组件。通用上传也兼容Servlet3.0以上的版本。
第一种方法编码上传步骤:
1.添加上传依赖包
2.编写上传页面
3.修改配置文件,增加上传配置
Spring MVC在默认情况下对文件上传的视图内容是不能解析的,要配置一个特别的解析器解析上传的内容,修改springmvc-servlet.xml配置文件
springmvc-servlet.xml配置内容:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8" />//默认上传编码utf-8
<property name="maxUploadSize" value="10485760000" />//上传最大限制
<property name="maxInMemorySize" value="40960" />//缓冲区大小
</bean>
4.
FreeMark
FreeMarker是一款模板引擎,即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算,之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据,而在模板之外可以专注于要展示什么数据。
1.设置freemarker的配置文件
<!-- 设置freeMarker的配置文件路径 -->
<bean id="freemarkerConfiguration"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:freemarker.properties" />
</bean>
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="freemarkerSettings" ref="freemarkerConfiguration" />
<!--扫描.ftl的模板文件-->
<property name="templateLoaderPath">
<value>/WEB-INF/freemarker/</value>
</property>
<!--设置一些常用的全局变量-->
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape" />
<entry key="webRoot" value="/shop"></entry>
<entry key="jsRoot" value="/shop/js"></entry>
</map>
</property>
</bean>
<!-- 配置freeMarker视图解析器 -->
<bean id="freemarkerViewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"
/>
<property name="viewNames" value="*.ftl" />
<property name="contentType" value="text/html; charset=utf-8" />
<property name="cache" value="true" />
<property name="suffix" value="" />
<!-- <property name="exposeRequestAttributes" value="true" />-->
<!--<property name="exposeSessionAttributes" value="true" />-->
<!--<property name="exposeSpringMacroHelpers" value="true" /> -->
<property name="order" value="0" />
</bean>
<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 通用解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="" />
<property name="viewNames" value="*.html,*.jsp" />
<property name="suffix" value="" />
<property name="viewClass"
value="org.springframework.web.servlet.view.InternalResourceView" />
<property name="order" value="1"></property>
</bean>
SpringMVC开发详解-总结
1.Controller
注意1:在新建Controller之前应该首先建一个包,因为SpringMVC是没法再默认包下运行的
注意2:类上的注解@RequestMapping(“/hi”)指定 Url路径前边一部分,方法上的注解@RequestMapping(“/say”)指定 Url路径最后一部分,也可以只把注解写在方法上,比如@RequestMapping(“/hi/say”)
2.修改url-pattern(web.xml)
注意:有关于ServletMapping的设置,通过这个设置,可以配置那些类型的url用那些servlet来处理
在开发中我们发现IDEA默认配置一个Dispatcher的Servlet(这个servlet使用org.springframework.web.servlet.DispatcherServlet这个类来处理),而这个servlet对应的url就是*.form
3.配置component-scan(dispatcher-servlet.xml)
注意:component-scan就是告诉Servlet去哪里找到相应的Controller
4.添加视图文件(.jsp)
注意:因为用户不能访问到WEB-INF路径下的资源,所以将创建好的view视图放在此路径下较安全
5.配置ViewResolver(dispatcher-servlet.xml)
注意:配置这一参数的原因是因为Controller中的返回值必须是View的绝对路径,所以在Controller中只想返回一个简写的话需要在dispatcher-servlet.xml文件中配置
<!--指定视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 视图的路径 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 视图名称后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
注意:记得修改完之后同步修改的Controller的返回值,不然又会报错404
6.通过Model向View传值
通过上面的操作已经完成了MVC中的VC了,所以M的修改开始
1.在Controller类里面修改
package wormday.springmvc.helloworld;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; // 这里导入了一个Model类
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/hi")
public class HiController {
@RequestMapping("/say")
public String say(Model model) { // 参数中传入Model
model.addAttribute("name","wormday"); // 指定Model的值
model.addAttribute("url","http://www.cnblogs.com/wormday/p/8435617.html"); // 指定Model的值
return "say";
}
}
2.然后打开View(.jsp)修改其中的值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
hello world,${name}//添加上JSTL表达式
<br/>${url}</body>
</html>
7.springMVC Controller返回值的可选类型详解
Spring MVC
支持ModelAndView/Model/ModelMap/Map/View/String/void
返回方式
1.ModelAndView
@RequestMapping("/hello")
public ModelAndView helloWorld() {
String message = "Hello World, Spring 3.x!";
return new ModelAndView("hello", "message", message);
}
总结:通过ModelAndView构造方法可以指定返回页面的名称,同时也可以通过setViewName()方法跳转到指定页面
2.Map
@RequestMapping("/demo2/show")
public Map<String, String> getMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value-1");
map.put("key2", "value-2");
return map;
}
总结:在前端页面.jsp页面中通过${key}获得到值,map.put()相当于request.setAttribute方法
3.View
可以返回文件格式
4.String
指定返回的视图页面名称,结合设置的返回地址路径加上页面名称后缀便能够访问到
注意:如果方法上声明了注解@ResponseBody,那么就会直接将返回值输出到前端页面
1.没有注解@ResponseBody的情况
@RequestMapping(value="/showdog")
public String hello1(){
return "hello";
}
2.在Controller控制器中有注解@ResponseBody的情况
@RequestMapping(value="/print")
@ResponseBody
public String print(){
String message = "Hello World, Spring MVC!";
return message;//返回前端结果输出界面处理 会直接将返回值输出到前端页面
}
3.在Controller控制器中有注解,返回JSON数据(使用Jackson)
@RequestMapping("/load1")
@ResponseBody
public String load1(@RequestParam String name,@RequestParam String password) throws IOException{
System.out.println(name+" : "+password);
//return name+" : "+password;
MyDog dog=new MyDog();
dog.setName("小哈");
dog.setAge("1岁");
dog.setColor("深灰");
ObjectMapper objectMapper = new ObjectMapper();
String jsonString=objectMapper.writeValueAsString(dog);
System.out.println(jsonString);
return jsonString;
}
5.void
如果返回值为空,那么响应的视图(View)页面对应为 访问地址
@RequestMapping("/index")
public void index() {
return;//这里表示的返回值为空,那么响应的访问地址是浏览器中输入的访问地址
}
总结:所以其对应的逻辑视图名为"index"
总结:
1.String作为请求处理方法的返回值类型是比较通用的方法,因为这样的逻辑视图名不会和请求的URL绑定,具有很强的灵活性,而模型数据又可以通过ModelMap控制
2.使用 void/map/Model 时,返回对应的逻辑视图名称真实url为:prefix前缀+视图名称 +suffix后缀组成
3.使用String,ModelAndView返回视图名称可以不受请求的url绑定,ModelAndView可以设置返回的视图名称
Spring MVC - FOD
1.几种Spring MVC 返回JSON数据比较
因为现阶段网站的前后端分离,所以让RESTful 接口开发成为后台开发的核心。JSON作为简单高效的数据交互格式是首选。Spring mvc 提供注解@ResponseBody协助处理返回数据格式,所以可以是JSON/XML
1.后端的配置
<beans:bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<beans:property name="supportedMediaTypes">
<beans:list>
<beans:value>application/json;charset=UTF-8</beans:value>
</beans:list>
</beans:property>
</beans:bean>
2.返回格式的比较
1.map格式
public @ResponseBody Map<String,Object> getData() {
return new HashMap<String,Object>;
}
注意:这种方式数据需要手动添加到map中。
2.业务类格式
public @ResponseBody User getData() {
return new User();
}
public @ResponseBody List<User> getData() {
return new User();
}
注意:这种方式可以看出返回的业务数据类型,但是如果返回的数据有变动,那么需要变更业务类。
3.JSON格式
//手动转换
public @ResponseBody JSONObject getData(){
User user = userDao.getUser();
JSONObject result = new JSONObject();
result.put("id",user.getId());
result.put("username",user.getUsername());
if(user.getSex()==0){
result.put("sex","男");
}else{
result.put("sex","女");
}
return result;
}
//自动转换
public @ResponseBody JSONObject getData(){
User user = userDao.getUser();
JSONObject result = JSONObject.fromObject(user);
return result;
}
图片上传
1.springmvc.xml配置文件(配置multipart类型解析器)
<!-- 文件上传 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
2.添加依赖
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
3.创建图片虚拟目录存储图片
4.上传图片程序
1.页面
<tr>
<td>商品图片</td>
<td>
<c:if test="${items.pic !=null}">
<img src="/pic/${items.pic}" width=100 height=100/>
<br/>
</c:if>
<input type="file" name="items_pic"/>
</td>
</tr>
2.controller
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(
Model model,
HttpServletRequest request,
Integer id,
@ModelAttribute("items")
@Validated(value = ValidGroup1.class)ItemsCustom itemsCustom,
BindingResult bindingResult,
MultipartFile items_pic
)throws Exception {
//原始名称
String originalFilename = items_pic.getOriginalFilename();
//上传图片
if(items_pic!=null && originalFilename!=null && originalFilename.length()>0){
//存储图片的物理路径
String pic_path = "D:\\tmp\\";
//新的图片名称
String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
//新图片
File newFile = new File(pic_path+newFileName);
//将内存中的数据写入磁盘
items_pic.transferTo(newFile);
//将新图片名称写到itemsCustom中
itemsCustom.setPic(newFileName);
}