SpringMvc上手学习
1基本组件
2流程分析
流程:前端控制器控制/请求,也就是全部请求来了都走进前端控制器(在servlet-mapping中设置),然后用户发送/hello请求,因为属于前端控制器的范围,因此它会响应用户的请求
3.详细的流程
现在的版本中,开启注解支持,默认帮我们导入处理映射器与处理适配器,因此我们只要定义:
-
前端控制器
-
视图解析器
就能执行,这就是原因
<!--开启springmvc注解支持 RequestMapping这些就是开启才会生效的(默认自带处理映射器与处理适配器)-->
<mvc:annotation-driven/>
请求参数绑定在Spring mvc中十分简单,我们只需要将方法的名字和请求的参数的key相同即可绑定成功
请求绑定在Spring mvc中十分简单,只需要请求参数名字和方法名相同即可
如果是对象,使用表单name值和字段名相同即可 如果对象中还有对象,则使用user.uName 这样的name即可
<form action="param/testParam2" method="post">
<%--类中的属性--%>
<input name="username" placeholder="姓名"/>
<input name="password" type="password" placeholder="密码">
<input name="money" placeholder="账户金额">
<%--对象--%>
<input name="user.uName" placeholder="用户名">
<%--list--%>
<input name="list[0].uName" placeholder="第一个list字段"/>
<input name="list[1].uName" placeholder="第一个list字段"/>
<%--map--%>
<input name="map['one'].uName" placeholder="第一个map字段"/>
<input name="map['two'].uName" placeholder="第二个map字段"/>
<button type="submit">提交</button>
</form>
4.过滤器
用于解决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.过滤器是servlet一部分,任何java web都可以用,而拦截器是springmvc自己的,只有springmvc框架才能使用
2.过滤器在url-pattren中配置了/*之后,可以对所有要访问的资源拦截,比如说包括controller,或者jsp,html,js等等
3.但是拦截器只会拦截控制器的方法,对于其他的资源是不会拦截的
总而言之:拦截器是springmvc特有的,它只拦截controller的方法 而过滤器是servlet的规范,它过滤配置路径下的一切资源
5.自定义类型转换器
因为date自动装配的时候,只要按照指定格式才能自动装配成功,否则报400客户端的错误,这时候就需要自定义类型转换器来实现我们的功能。
5.1实现Converter接口
import org.springframework.core.convert.converter.Converter;
public class String2DateConverter implements Converter<String, Date> {
5.2配置自定义的类型转换器
<!--类型转换器-->
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters" ref="string2DateConverter"/>
</bean>
<bean id="string2DateConverter" class="com.jd.nxj.utils.String2DateConverter"/>
5.3在这里加入配置,代表自定义类型转换器
<!--开启springmvc注解支持 RequestMapping这些就是开启才会生效的(默认自带处理映射器与处理适配器)-->
(这个注解默认处理映射器与处理适配器生效,但是类型转换器并没有默认生效,因此我们在这里配置一下)
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>
6获取Servlet原生API
<a href="param/testServlet">获取原生API只需要在方法参数中加上即可</a>
//获取原生API
7常用注解
7.1 RequestParam
说明:自动装配的名字和我参数名不同,我可以通过这个注解指定
<a href="testRequestParam?n=nxj">RequestParam</a>
7.2 RequestBody
<form action="testRequestBody" method="post">
姓名:<input name="user"/><br/>
密码:<input name="pass"/><br/>
<input type="submit" value="提交"/>
</form>
7.3 PathVaraible
<a href="testPathVariable/nxj">PathVariable</a>
如何发出POST,DELETE等请求方式
(这个不用急,配置比较麻烦,以后需要用的时候百度一下就好)
7.4RequestHeader
用的很少(获取请求头信息)
<a href="testRequestHeader">RequestHeader</a>
7.5CookieValue
用的很少(获取Cookie信息)
<a href="testCookieValue">CookieValue</a>
7.6ModelAttribute
-
放在方法上,则是在调用controller之前执行这个方法(什么意思呢?就是只要你的这个请求走进了某个controller,那么这个controller下标注了@ModelAttribute注解的方法都会在调用前执行)
//Person 中只有name与date两个字段 @RequestMapping("/testModelAttribute") public String testModelAttribute(Person person){ System.out.println("testModelAttribute执行"); System.out.println(person); return "success"; } @ModelAttribute public Person testMethod(String name){//name和传进来的是一样的 System.out.println(name); Person person=new Person(); person.setName("qwe");//原来有的不会覆盖,原来没有的则覆盖 person.setDate(new Date()); return person; }
<form action="testModelAttribute" method="post"> 姓名:<input name="name"/><br/> <input type="submit" value="提交"/> </form>
另一种无返回值的
@RequestMapping("/testModelAttribute") public String testModelAttribute(Person person,@ModelAttribute(value = "abc") Person person1){ System.out.println("testModelAttribute执行"); System.out.println(person);//Person{name='宁新杰', date=null} System.out.println("=="); System.out.println(person1);//Person{name='宁新杰', date=Fri Nov 20 20:15:32 CST 2020} return "success"; } @ModelAttribute public void testMethod(String name, Map<String,Object> map){ System.out.println("这里是AnnotationController"); System.out.println(name); Person person=new Person(); person.setName("qwe");//原来有的不会覆盖,原来没有的则覆盖 person.setDate(new Date()); map.put("abc",person); }
7.7SessionAttribute
这里有Model(就是存放到request中)
(这个不要看这个注解了 , 学习中用到的是SessionAttributes,只能标注在类上)
什么叫Restful风格?
请求地址都一样,根据不同的请求方式(如POST,GET,PUT,DELETE等)选择不同的方法执行
8返回值为String的页面跳转
//返回值类型为String
<h1>this is success page</h1>
<div style="color: aquamarine">
<h1>testString</h1>
${user.toString()}
</div>
9无返回值的页面跳转实现
//返回值类型为void
10forward转发于redirect重定向
在强调一下:forward是系统内部资源转发,因此它能转发到WEB-INF下的资源,而redirect是外部重定向,因此重定向是无法直接访问WEB-INF下的资源
使用关键字进行使用的时候不会经过视图解析器,因此我们需要写全
@RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect"); return "forward:/WEB-INF/pages/success.jsp"; return "redirect:/user/testString"; //其中/user是class上requestMapping ;/testString是他下面的一个方法的requestMapping。 return "redirect:/index.jsp";// 使用关键字的时候不需要加项目名称,因此框架底层帮我们做了,但是上面那代码直接调用就需要加。 }
####
11设置静态资源不拦截(js,css,图片等)
<!--设置哪些静态资源不拦截(因为我们的前端控制器设置拦截/ 也就是所有的,因此这里我们需要设置哪些不需要拦截)--> <!--mapping映射的后面需要加** location不要加 我加了** 还是出不来--> <mvc:resources mapping="/js/**" location="/js/"/>
12ModelAndView
Model和View,也就是设置请求域值然后返回页面
@RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ ModelAndView modelAndView=new ModelAndView(); User user=new User("nxj","132",23); //也会将对象存入到request域中 modelAndView.addObject("user_mv",user); modelAndView.setViewName("success");//跳转到success页面(走视图解析器) return modelAndView; }
13Ajax操作(@RequestBody,@ResponseBody)
(我以后主要干的是后端,看这里的目的是用到了两个注解,一个是@RequestBody一个是@ResponseBody 一个是接受请求域中的消息体,一个是将消息体响应出去,现在知道他们的区别了吧!)
(我们使用json来操作的,需要导入相应的jar包)
整体是这样:ajax发送的时候url绑定到controller方法,ajax中data中的数据在controller下通过@RequestBody获取,ajax中的success的回调参数的数据,我们controller通过返回值前加@ResponseBody进行返回
$(function(){
$("#btn").click(function () {
$.ajax({
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data :'{"username":"nxj","password":"456"}',
dataType:"json",
type:"post",
success:function (data) {
}
});
})
});
14.异常处理
发生异常,我们向上抛,抛到了前端控制器,我们来处理,如果他不做处理则直接给浏览器,非常不好
-
编写自定义异常
-
编写异常处理器(需要实现HandlerExceptionResolver)
-
配置异常处理器
//自定义异常 public class MyException extends Exception { public MyException( String message) { this.message = message; } //存储异常提示信息 private String message; @Override public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
//异常处理器类 public class MyExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { String message = ex.getMessage(); MyException myEx=null; if(ex instanceof MyException){ myEx=(MyException)ex; } else { myEx=new MyException("系统正在维护..."); } ModelAndView modelAndView=new ModelAndView(); modelAndView.setViewName("error"); modelAndView.addObject("error_msg",myEx.getMessage()); return modelAndView; } }
<!--配置异常处理器(加入到组件中即可)--> <bean id="myExceptionResolver" class="com.jd.nxj.exceptions.MyExceptionResolver"/>
15拦截器
-
编写拦截器类(需要实现HandlerInterceptor)
-
配置拦截器
//自定义拦截器
public class MyInterceptor1 implements HandlerInterceptor {
//预处理(controller方法执行前,先走的它 )
//return true 代表放行,走下一个拦截器(如果没有则直接执行controller中的方法)
//return false 代表拦截,我们可以通过request,response 跳转到提示页面等
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--要拦截的方法-->
<mvc:mapping path="/my/*"/>
<bean class="com.jd.nxj.interceptor.MyInterceptor1"/>
<!--不要拦截的方法-->
<!--<mvc:exclude-mapping path="com.jd.nxj.interceptor.MyInterceptor1"/>-->
</mvc:interceptor>
</mvc:interceptors>
配置多个拦截器,他是链式走的,也就是先走1,再走2,方法执行完,回头走2,再走1,然后页面显示,然后页面加载完2,然后页面加载完1;这是放行的整个流程。
//自定义拦截器
public class MyInterceptor1 implements HandlerInterceptor {
//预处理(controller方法执行前,先走的它 )
//return true 代表放行,走下一个拦截器(如果没有则直接执行controller中的方法)
//return false 代表拦截,我们可以通过request,response 跳转到提示页面等
//自定义拦截器 public class MyInterceptor2 implements HandlerInterceptor { //预处理(controller方法执行前,先走的它 ) //return true 代表放行,走下一个拦截器(如果没有则直接执行controller中的方法) //return false 代表拦截,我们可以通过request,response 跳转到提示页面等 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle222"); //request.getRequestDispatcher("/WEB-INF/pages/warn.jsp").forward(request,response); return true; } //方法执行后走这个(页面加载前) @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle222"); //request.getRequestDispatcher("/WEB-INF/pages/warn.jsp").forward(request,response);//我转发到这里,这样原来想跳转的就跳不过去,因为我先执行了 } //页面加载后走这个 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion222"); } }
<!--配置拦截器--> <mvc:interceptors> <!--第一个拦截器--> <mvc:interceptor> <!--要拦截的方法--> <mvc:mapping path="/my/*"/> <bean class="com.jd.nxj.interceptor.MyInterceptor1"/> <!--不要拦截的方法--> <!--<mvc:exclude-mapping path="com.jd.nxj.interceptor.MyInterceptor1"/>--> </mvc:interceptor> <!--第二个拦截器--> <mvc:interceptor> <!--要拦截的方法--> <mvc:mapping path="/my/*"/> <bean class="com.jd.nxj.interceptor.MyInterceptor2"/> <!--不要拦截的方法--> <!--<mvc:exclude-mapping path="com.jd.nxj.interceptor.MyInterceptor1"/>--> </mvc:interceptor> </mvc:interceptors>
@RequestMapping("/test") public String test(){ System.out.println("test"); return "success"; }
#结果 preHandle11 preHandle222 test postHandle222 postHandle11 hello page execute method afterCompletion222 afterCompletion11
SpringMVC.xml
不太全
web.xml
SSM需要的pom文件
<dependencies> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> <scope>runtime</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> <scope>provided</scope> </dependency> <!--日志--> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> <scope>test</scope> </dependency> <!--mybatis--> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> <!-- https://mvnrepository.com/artifact/c3p0/c3p0 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies>
Spring整合SpringMVC
Spring-web中提供了这个监听器:ContextLoaderListener
监听器默认只加载WEB-INF下的applicationContex.xml
<!--配置Spring的监听器,默认只加载WEB-INF目录下的applicationContext.xml配置文件--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--设置配置文件的目录--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
以下是mapper.xml 自己看看记一下这块
<resultMap type="com.jd.b2b.central.control.entity.Category" id="CategoryMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="extendId" column="extend_id" jdbcType="INTEGER"/>
<result property="firstClass" column="first_class" jdbcType="INTEGER"/>
<result property="firstClassName" column="first_class_name" jdbcType="VARCHAR"/>
<result property="secondClass" column="second_class" jdbcType="INTEGER"/>
<result property="secondClassName" column="second_class_name" jdbcType="VARCHAR"/>
<result property="createUser" column="create_user" jdbcType="VARCHAR"/>
<result property="updateUser" column="update_user" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
<result property="yn" column="yn" jdbcType="TINYINT"/>
<result property="ts" column="ts" jdbcType="TIMESTAMP"/>
</resultMap>
<!--查询单个-->
<select id="queryById" resultMap="CategoryMap">
select
id, extend_id, first_class, first_class_name, second_class, second_class_name, create_user, update_user, create_time, update_time, yn, ts
from category
where id = #{id}
</select>
Spring整合Mybatis
spring如何整合mybatis呢?想想看,我们mybatis需要调用SqlSessionFactory生成SqlSession,通过SqlSession调用数据库,那么我们如果将SqlSession放到Spring的容器中,岂不是就可以注入了,就是这个思想!
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</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-web</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-test</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}