SpringMVC是什么?
- Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架
- 将web层进行职责解耦
- 简化开发
springmvc工作流程图:
栗子:
举一个springMVC栗子
1.导包
具体需要什么包就不一 一解释了
2.配置web.xml
配置DisPatcherServlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<display-name></display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list>
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
</web-app>
|
3.配置springmvc.xml
1.头文件约束
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" 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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
- 后端控制器(controller )交给spring来管理、配置处理器映射器、处理器适配器、配置视图解析器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<bean name="/test" class="com.gec.controller.first"></bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
|
4、在web.xml中配置springmvc核心文件启动
1 2 3 4 5 6
|
<init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param>
|
5、测试
新建一个后台控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.gec.controller;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class first extends AbstractController { @Override protected ModelAndView handleRequestInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { return new ModelAndView("index"); } }
|
新建一个hello world 界面
1 2 3 4 5 6 7 8 9 10
| <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>springmvc hello!!!!!!!!!!</h1> </body> </html>
|
改进:
处理器映射器、处理器适配器、视图解析器三大核心组件都是目前都是使用xml方式配置。
上面的开发太过复杂,springmvc.xml文件中处理器映射器、处理器适配器、视图解析器 ,这些东西都有springmvc框架帮我做了
配置注解的处理器映射器和处理器适配器
- 凭什么处理器映射器、处理器适配器可以省略呢?
开发总结:
处理器映射器 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
1)负责寻找SpringMVC项目中哪个后端控制器去执行任务
2)寻找到对应的后端控制器之后返回给前端控制器 (DispatcherServlet)
处理器适配器 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
1)根据处理器映射器找到的 后端控制器 去执行该 后端控制器
2)执行完毕后,返回ModleAndView
视图解析器 org.springframework.web.servlet.view.InternalResourceViewResolver
1)根据处理器适配器执行的后的ModelAndView进行解析
以上三大核心组件都是目前都是使用xml方式配置
由于以上的xml配置非常的繁琐,虽然 SpringMVC中三个组件可以省略不写,我们也知道为什么呢?但是 后端控制器无法省略,因为如果省略了,那么SpringMVC将无法进行处理请求和响应
注意:如果只配置了一个最新的处理器映射器,而最新的处理器适配器没有配置,则直接抛出异常信息!
经过上面的配置,也就是说,如果我们既想使用注解开发SpringMVC也想提高一些性能方面的东东,我们必须写下面的配置
完整配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <context:component-scan base-package="com.shop.web"></context:component-scan>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
|
由于每次都要写上那么多配置,所以SpringMVC官方推出一个
1 2 3 4 5 6 7 8 9 10 11 12
| <context:component-scan base-package="com.gec.controller"></context:component-scan>
<mvc:annotation-driven/><mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"></property> <property name="suffix" value=".jsp"></property> </bean>
|
注解代替后端处理控制器
1 2 3 4 5 6 7 8 9 10
| @Controller public class homeContoller{ @RequestMapping(value="/index") public ModelAndView aa() { return new ModelAndView("index"); } }
|
SSM整合
Spring + Spring MVC + Mybatis
举个栗子:
1.导包(贼多)
2.建立目录结构
3.创建数据库
4.逆向工程生成
5.编写配置文件
mybatis
1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> </configuration>
|
dao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<context:property-placeholder location="classpath:db.properties" /> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driverName}" /> <property name="url" value="${urlName}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <property name="maxActive" value="10" /> <property name="maxIdle" value="5" /> </bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:mybatis-config.xml" /> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.shop.dao"/> </bean>
</beans>
|
service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<context:component-scan base-package="com.shop.service"></context:component-scan> </beans>
|
transaction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mvc" /> <property name="username" value="root" /> <property name="password" value="root" /> <property name="maxActive" value="10" /> <property name="maxIdle" value="5" /> </bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="SUPPORTS" read-only="false"/> <tx:method name="insert*" propagation="SUPPORTS" read-only="false" /> <tx:method name="delete*" propagation="SUPPORTS" /> <tx:method name="update*" propagation="SUPPORTS" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.shop.service.*.*(..))" /> </aop:config> </beans>
|
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param> <param-name>ContextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
|
- load-on-startup 元素标记容器是否应该在web应用程序启动的时候就加载这个servlet,(实例化并调用其init()方法)。
- 它的值必须是一个整数,表示servlet被加载的先后顺序。
- 如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时再加载。
- 如果值为正整数或者0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载。值相同时,容器就会自己选择顺序来加载。
bug
1 2 3
| <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
|
在web.xml中使用监听器加载springIOC,会报错找不到ContextLoaderListener类
解决方案:直接用
1 2 3 4 5 6
| <init-param> <param-name>ContextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup>
|
springmvx.xml中写入
1 2 3
| <import resource="applicationContext-dao.xml"/> <import resource="applicationContext-service.xml"/> <import resource="applicationContext-transaction.xml"/>
|
1.SpringMVC中参数传递
1.View to Controller
SpringMVC对前端传来的参数-自动封装
1.基本类型
Int float String double
login.jsp
1 2 3 4 5
| <form action="${pageContext.request.contextPath}/login/add" method="post"> <input type="text" name="name"><br/> <input type="submit" value="提交"> </form> </body>
|
loginController
1 2 3 4 5 6 7 8 9 10
| @Controller @RequestMapping(value="/login") public class loginController { @RequestMapping(value="/add") public ModelAndView add(String name) { System.out.println(name); return null; } }
|
对于基本类型直接通过参数的形式接收
2.实体对象封装
user
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class User { private String name; private Integer age; private String gender; @Override public String toString() { return "User [name=" + name + ", age=" + age + ", gender=" + gender + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } }
|
1 2 3 4 5 6 7 8 9
| <body> <form action="${pageContext.request.contextPath}/login/delete" method="post"> 姓名:<input type="text" name="name"><br /> 年龄:<input type="text" name="age"><br /> 性别:<input type="text" name="gender"><br /> <input type="submit" value="提交"> </form>
|
1 2 3 4 5 6
| @RequestMapping(value="/delete") public ModelAndView delete(User user) { System.out.println(user); return null; }
|
springmvc直接将参数封装成对象返回给contoller
3.list
4.Map
2.requestMapping
实际开发中,一个项目会有很多个模块,比如用户管理(UserController)、订单管理(OrderController)、产品管理(ProductController)等众多模块,而每个模块中都会有添加、删除、修改、更新等操作?
1.作用在类上
url地址: http://localhost:8080/spring03/add
@RquestMapping加在方法上,还可以加在类上.
1 2 3 4 5 6 7 8 9 10
| @Controller @RequestMapping(value="/Index") public class IndexController{ @RequestMapping(value="/add") public ModelAndView aa(String name) { System.out.println("name:"+name); return new ModelAndView("/WEB-INF/jsp/index.jsp"); } }
|
【开发小结】:@RequestMapping映射的请求信息必须保证全局唯一
2.限定请求参数
@RquestMapping作为请求的一个映射,除了可以配置url地址,还可以配置请求方式,还可以在请求时,限定请求参数
value=”/aaa”
method=RequestMethod.GET
params=”username”
1 2 3 4 5 6 7 8 9 10 11
| @Controller @RequestMapping("/order") public class OrderController { @RequestMapping(value="/aaa",method=RequestMethod.GET,params="username") public ModelAndView index(String name) { System.out.println("...."+name); return new ModelAndView("index"); } }
|
同时支持get和post请求
测试请求类型
测试请求参数名称
3.SpringMVC中参数传递
1.Controller to View
方式一:
使用ModelAndView
ModelAndView:控制器处理方法的返回值若为ModelAndView,则既包含视图信息,又包含模型数据信息。
ModelAndView addObject(String attributeName, Object attributeValue)
;
ModelAndView addAllObjects(Map<String,?> modelMap);
void setView(View view);
void setViewName(String viewName);
方式二:
直接使用Model
控制器处理方法的返回值为String(逻辑视图名),模型数据信息放入到Model中即可。
Model的数据结构,处理方法的入参为Model类型即可
springMVC会隐式帮我们创建一个model对象,所以不需要new
1 2 3 4 5
| @RequestMapping(Value="aa2") public String index(Model m){ m.addAttribute("hello","hello springmvc"); return " index"; }
|
Model对象的用法:
- 使用Model对象,通过key-value键值方式存储值,在视图层使用key来获取对应的值。
- 使用Modle对象,我们可以不指定任何的key,只需要传入一个值就可以了,但是需要注意,如果不传入任何的key,那么在视图(jsp)中获取的时候,使用该对象的类型作为key来获取。
此处对象的类型一定必须是小写
例如:字符串 -> string
如果使用大写那么不会报错吗,但是结果出不来
Model其实本质上就是一个Map,那么我们是否可以使用Map作为参数直接入参呢? 可以
方式三
4.乱码问题
1.post乱码
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <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>
|
以上可以解决post请求乱码问题。
2.get乱码
对于get请求中文参数出现乱码解决方法有两个:
方式一:
修改tomcat配置文件添加编码与工程编码一致,如下:
方式二
对参数进行重新编码:
String username= new String(request.getParamter(“userName”).getBytes(“ISO8859-1”),”utf-8”)
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码
5.VO
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 查询条件: <table width="100%" border=1> <tr> <td>商品名称:<input type="text" name="product.name"></td> <td>商品价格:<input type="text" name="product.price"></td>
<td>姓名:<input type="text" name="user.username"></td> <td>性别:<input type="text" name="user.sex"></td>
<td><input type="submit" value="查询"/></td>
|
注意:输入框的name属性
创建一个VO类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class QueryVo { private Product product; private User user;
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
public Product getProduct() { return product; }
public void setProduct(Product product) { this.product = product; } }
|
控制类接收前端参数
1 2 3 4 5 6
| @RequestMapping(value="/query") public ModelAndView query(QueryVo vo) { return null; }
|
直接用QueryVo接收参数
6.自定义转换器
时间日期转换
1.自定义转换器类
(实现converter接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class CustomerConveter implements Converter<String, Date>{ @Override public Date convert(String source) { try { Date date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(source); return date; } catch (ParseException e) { e.printStackTrace(); } return null; }
}
|
2.springmvc.xml配置
springMVC.xml配置自定义转换器
将自定义的转换器关联到FormattingConversionServiceFactoryBean
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <bean name="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.shop.conveter.CustomerConveter"></bean>
</set> </property> </bean>
|
4.转换器挂载
1 2 3
| <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
|
7.绑定参数
数组
List
批量删除(数组传值)
jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>查询商品列表</title> </head> <body> <form action="${pageContext.request.contextPath }/deleteAll" method="post"> 批量删除: <table width="100%" border=1> <tr> <!-- <td>商品名称:<input type="text" name="product.name"></td> <td>商品价格:<input type="text" name="product.price"></td>
<td>姓名:<input type="text" name="user.username"></td> <td>性别:<input type="text" name="user.sex"></td> -->
<td><input type="submit" value="批量删除"/></td> </tr> </table> 商品列表: <table width="100%" border=1> <tr> <td></td> <td>商品名称</td> <td>商品价格</td> <td>生产日期</td> <td>商品描述</td> <td>操作</td> </tr> <c:forEach items="${productList }" var="item"> <tr> <td><input type="checkbox" name="ids" value="${item.id }"></td> <td>${item.name }</td> <td>${item.price }</td> <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td> <td>${item.detail }</td> <td><a href="${pageContext.request.contextPath }/itemEdit?id=${item.id}">修改</a></td>
</tr> </c:forEach>
</table> </form> </body> </html>
|
创建一个QueryVo
1 2 3 4 5
| public class QueryVo { private Product product; private User user; private Integer[]ids;
|
ProductController接收参数
1 2 3 4 5 6 7
| @RequestMapping(value="/deleteAll") public ModelAndView deleteAll(QueryVo vo) { System.out.println(vo); return null; }
|
8.springMVC文件上传
SpringMVC 中,文件的上传,是通过 MultipartResolver 实现的。 所以,如果要实现文件的上传,只要在 spring-mvc.xml 中注册相应的 MultipartResolver 即可。
MultipartResolver 的实现类有两个:
CommonsMultipartResolver
StandardServletMultipartResolver
两个的区别:
第一个需要使用 Apache 的 commons-fileupload 等 jar 包支持,但它能在比较旧的 servlet 版本中使用。
第二个不需要第三方 jar 包支持,它使用 servlet 内置的上传功能,但是只能在 Servlet 3 以上的版本使用
1、导包
2、jsp准备
1.提供一个File上传表单控件
2、指定表单类型
1 2 3
| !-- 上传图片是需要指定属性 enctype="multipart/form-data" --> <form id="itemForm" action="${pageContext.request.contextPath }/updateProduct" method="post" enctype="multipart/form-data">
|
3.配置CommonsMultipartResolver类
在springmvc中配置
1 2 3 4 5
| <bean name="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5242880" /> </bean>
|
注意:这个类必须起这个名字不然会报500错误,说找不到这个类
4、上传控制类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @RequestMapping("/updateitem.action") public void update(Product product,HttpServletRequest req, HttpServletResponse resp, MultipartFile pictureFile) throws IOException {
int lastIndexOf = pictureFile.getOriginalFilename().lastIndexOf("."); String subfix = pictureFile.getOriginalFilename().substring(lastIndexOf); String filename = ""+UUID.randomUUID().toString()+subfix;
String path=req.getServletContext().getRealPath("/images"); pictureFile.transferTo(new File(path+File.separator+filename)); product.setPic(filename); int update = productservice.update(product); if(update>0){ System.out.println("更新成功"); }else { System.out.println("更新失败"); } resp.sendRedirect("/product"); }
|
getOriginalFilenmae()
得到上传文件的名字
5、查看上传文件
由于web.xml文件中,前端处理器(DispatcherServlet)的原因,会将所有请求拦截,之放行.jsp文件
1 2 3 4 5 6 7 8
| <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <servlet-mapping> <servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern> </servlet-mapping>
|
所以在springMVC.xml文件中要放行资源
1 2 3 4 5 6 7 8 9
| <mvc:resources mapping="/images/**" location=" /images/"></mvc:resources>
|
mapping 表示url访问路径 ef:http://localhost:8080/images/ftp.txt
location:表示本地项目文件目录
9、json数据交互
1、导包
前端传递json到contoller
编写ajax
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <script src="/js/jquery-1.8.3.min.js"></script> <script>
$(function(){ $("#btn").click(function () { $.ajax({ url:"${pageContext.request.contextPath}/test01", contentType:"application/json;charset=utf-8", data:{'name':'iphoneX', 'price':8000.9}, success:function (data) { alert(data); } } ) } ) }) </script>
|
400错误
出现这个请求无效说明请求没有进入后台服务器里
原因: (1)前端提交的字段名称或者字段类型和后台的实体类不一样 或者前端提交的参数跟后台需要的参数个数不一致,导致无法封装
(2)前端提交到后台的数据应该是JSON字符串类型,而前端没有将对象转化为字符串类型;
解决方法: 对照字段名称,类型保证一致
编写controller
1 2 3 4 5
| @RequestMapping(value = "/test01") public void test01(Product product){ System.out.println(product); System.out.println("接收参数成功"); }
|
注意:前端传递的json数据也会被转到对象中,springmvc帮我们做了
后端转递json到前端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RequestMapping(value = "/test02") @ResponseBody public List<Product>test02(Product product){ ArrayList<Product> list = new ArrayList<>(); Product p1 = new Product(); Product p2 = new Product(); Product p3 = new Product(); p1.setName("123"); p2.setName("123"); p3.setName("123"); list.add(p1); list.add(p2); list.add(p3); System.out.println(product); System.out.println("接收参数成功"); return list; } 结果:
|
用@ResponseBody 实现将对象转json,springmvc已经风好
@ResponseBody可以放在方法上,表示这个方法返回数据转成json;也可以放在类上,表示这个类所有方法都参数都转成json.
如果@ResponseBody用在类上,可以用**@RestController**,替代@controller和@ResponseBody,它后面两个注解的合体。如图;
10、Restful风格
1、什么是Restful
REST: Representational State Transfer,即表述性转移,是一种软件架构的风格(一个规范),不是一门技术[e1] 。
[e1]PHP、NET、Java中都有
传统方式:
https://movie.douban.com/subject?id=26416062
restful
风格:https://movie.douban.com/subject/26416062
2、REST风格好处:
3. RESTful使用
使用springMVC+REST改造前面的商品案例。
1
| <td><a href="${pageContext.request.contextPath }/itemEdit/${item.id}">修改</a></td>
|
- 在控制器方法参数的前面加上**@PathVariable**注解 =========解析rest风格
1 2 3 4 5 6 7 8
| @RequestMapping(value="/itemEdit/{id}") public ModelAndView getProductById(@PathVariable("id")Integer aa,HttpServletRequest req, HttpServletResponse response, HttpSession ss) { Product product = productservice.getProductById(aa); }
|
11、controller方法返回类型
controller方法返回值(指定返回到哪个页面, 指定返回到页面的数据)
modelAndView.addObject(“itemList”, list); 指定返回页面的数据
modelAndView.setViewName(“itemList”); 指定返回的页面
返回普通字符串,就是页面去掉扩展名的名称, 返回给页面数据通过Model来完成
- 返回void(使用它破坏了springMvc的结构,所以不建议使用)
可以使用request.setAttribut 来给页面返回数据
可以使用request.getRquestDispatcher().forward()来指定返回的页面
如果controller返回值为void则不走springMvc的组件,所以要写页面的完整路径名称
1、返回void (不推荐)
使用它破坏了springMvc的结构,所以不建议使用。这是servlet原生的,mvc已经将它封装好了。
转发:
1 2 3 4 5
| @RequestMapping(value="/test") public void test(HttpServletRequest req,HttpServletResponse response) throws ServletException, IOException { req.setAttribute("msg", "阿黄很大~~~"); req.getRequestDispatcher("/WEB-INF/jsp/demo.jsp").forward(req, response); }
|
重定向:
1 2 3 4 5 6
| @RequestMapping(value="/test") public void test(HttpServletRequest req,HttpServletResponse response) throws ServletException, IOException { response.sendRedirect("/ssm5/list"); }
|
2、.ModelAndView(一般)
1 2
| modelAndView.addObject("itemList", list); modelAndView.setViewName("itemList");
|
3、String
推荐使用String类型
1、普通跳转
返回普通字符串,就是页面去掉扩展名的名称,返回给页面数据通过Model来完成。
1 2 3 4 5 6 7 8
| @RequestMapping(value="/updateProduct") public String updateProduct(Product product,Model model) throws ServletException { productservice.update(product); model.addAttribute("xxx",”xxxx”); return " productItem "; }
|
2、请求转发
1 2 3 4 5 6 7 8
| @RequestMapping(value="/updateProduct") public String updateProduct(Product product,Model model) throws ServletException { productservice.update(product); model.addAttribute("msg","今天天气不错呀"); return "forward:list"; }
|
3、请求重定向
1 2 3 4 5 6 7 8 9
| @RequestMapping(value="/updateProduct") public String updateProduct(Product product,Model model) throws ServletException { productservice.update(product); model.addAttribute("msg","今天天气不错呀"); return "redirect:list"; }
|
12、自定义异常
思想:做一个全局异常处理器,处理所有没有处理过的运行时异常用于更友好地提示用户。
1、定义全局异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class myException implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
String msg="出现bug了,请联系管理员处理";
if(e instanceof MyException2){ msg = ((MyException2) e).getMsg(); } ModelAndView mv = new ModelAndView(); mv.addObject("msg",msg); mv.setViewName("error"); return mv; } }
|
2、自定义异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class MyException2 extends Exception{ String msg;
public String getMsg() { return msg; }
public void setMsg(String msg) { this.msg = msg; }
public MyException2() { super(); }
public MyException2(String message) { super(); this.msg=message; } }
|
3、注册异常
在springmvc.xml中注册全局异常
1 2
| <bean class="com.shop.myException.myException"></bean>
|
4、编写异常界面
1 2 3 4 5 6 7 8 9 10
| <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>${msg}</h1> </body> </html>
|
5、测试:
制造异常
1 2 3 4 5 6 7 8 9
| @RequestMapping(value="/exception") public ModelAndView exception() throws MyException2 { if(true){ throw new MyException2("找不到商品"); }
}
|
13、拦截器
1、定义
Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
实现HandlerInterceptor接口,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| Public class HandlerInterceptor1 implements HandlerInterceptor{
@Override Public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Return false; }
@Override Public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { }
@Override Public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }
}
|
2、拦截器配置
1、针对某种mapping
1 2 3 4 5 6 7 8 9 10
| <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="interceptors"> <list> <ref bean="handlerInterceptor1"/> <ref bean="handlerInterceptor2"/> </list> </property> </bean> <bean id="handlerInterceptor1" class="com.shop.intercept.interceptor"/> <bean id="handlerInterceptor2" class="com.shop.intercept.interceptor"/>
|
2、针对所有mapping配置全局拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.shop.springmvc.filter.HandlerInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.shop.springmvc.filter.HandlerInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors>
|
或者
1 2 3 4 5 6 7
| <bean name="hi2" class="com.shop.intercept.interceptor"></bean> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <ref bean="hi2"></ref> </mvc:interceptor> </mvc:interceptors>
|
3、流程测试
1 2 3 4 5 6 7 8
| public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {}
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}
|
以上三者的执行流程
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2,每个拦截器的preHandler方法都返回true。
1、运行流程
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor2..postHandle..
HandlerInterceptor1..postHandle..
HandlerInterceptor2..afterCompletion..
HandlerInterceptor1..afterCompletion..
2、中断流程测试
从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的所有方法不执行,且controller也不执行了。
HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,运行流程如下:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor1..afterCompletion..
3、总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用 ,afterCompletion只有preHandle返回true才调用
登录拦截
1、编写拦截器
实现HandlerInterceptor接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class interceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println("controller执行前调用此方法"); String requestURI = httpServletRequest.getRequestURI();
if(requestURI.endsWith("login")){ return true; }else { HttpSession session = httpServletRequest.getSession(false); if(null!=session){ User user = (User) session.getAttribute("user"); if(null!=user) if(user.getUsername()!=null){ System.out.println(user.getUsername()); return true; } } httpServletResponse.sendRedirect("/tologin"); System.out.println("重定向跳转登录界面"); return false; } }
@Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("controller执行后但未返回视图前调用此方法"); }
@Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("controller执行后且视图返回后调用此方法"); }
|