SpringMVC-XML开发
# SpringMVC开发步骤
- 导入SpringMVC相关坐标
<!-- spring mvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.6</version> </dependency>
- 在web.xml中配置SpringMVC核心控制器DispathcerServlet
<!--配置SpringMVC的前端控制器--> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- 加载spring-mvc 配置文件--> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> <!-- 所有请求都要走 这个--> </servlet-mapping>
- 创建Controller类(代替以前的servlet类),并使用注解配置Controller类中业务方法的映射地址
@Controller("usercontroller1") @RequestMapping("/user") public class UserController { //页面跳转1 -- 返回字符串 //请求方法和网站之间的映射关系 @RequestMapping(value = "/quick1",method = RequestMethod.GET,params = {"username"}) public String save(){ System.out.println("Controller save running……"); //return "/jsp/success.jsp"; //每个网页的前缀都是 /jsp/ 后缀都是 .jsp return "success"; //指定内部资源解析器后 省略前缀和后缀 //return "redirect:/jsp/success.jsp"; //不能省略前缀和后缀 } //回写数据4 --- 先返回User对象 ,然后SpringMVC帮忙转换成JSON字符串(需要导入依赖坐标) @RequestMapping(value = "/response4") @ResponseBody public User res4() throws IOException { //这里虽然返回的是User对象,但是经过处理器适配器后 会转换成JSON字符串 //模拟数据获取 User user=new User(); user.setUsername("凉冰"); user.setPassword("123"); return user; } }
编写视图页面(.jsp .html)
配置SpringMVC核心配置文件spring-mvc.xml
………………………… <!-- Controller 组件扫描--> <context:component-scan base-package="com.diana.controller"/> …………………………
- 客户端发起请求测试
# SpringMVC 组件解析


# SpringMVC 数据响应
@RequestMapping的参数 --->请求方法和网站之间的映射关系
@RequestMapping(value = "/quick1",method = RequestMethod.GET,params = {"username"}) 1.value 用于指定请求的url 2.method 用于指定请求的方式 3.params 用于指定限制请求参数的条件 params={"username"} 表示请求参数中必须要用username params={"money!=100"} 表示请求参数中money不能是100放到类名头上,表示进入该类的方法都需要加前缀 /user @RequestMapping("/user") public class UserController{} 放到方法名头上,表示执行该方法的最后路径 /quick1 @RequestMapping(value = "/quick1",method = RequestMethod.GET,params = {"username"}) public String save(){} 即要想执行save方法,则 ../user/quick1页面跳转
1.返回String字符串(success)形式 与前(/jsp/)后(.jsp)缀拼好后,默认进行转发(forward) forward:/jsp/success.jsp 重定向的话 redirect:/success.jsp 2.返回ModelAndView类型 model: 模型 用来封装数据 view: 视图 用来展示数据 ---与上面返回方式一样,拼字符串访问<!--配置内部资源视图解析器--> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 设置默认前缀和后缀 --> <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> </bean>回写数据
@ResponseBody 作用
设置当前控制器返回值作为响应体
回写json数据
//回写数据4 --- 直接返回User对象 ,SpringMVC自动将对象转换成JSON字符串(需要导入依赖坐标) @RequestMapping(value = "/response4") @ResponseBody public User res4() throws IOException { //这里虽然返回的是User对象,但是经过处理器适配器后 会转换成JSON字符串 //模拟数据获取 User user=new User(); user.setUsername("凉冰"); user.setPassword("123"); return user; }1.直接返回字符串 * 使用response对象,response.getWriter().write("hello world"); --不推荐 * 使用@ResponseBody 注解 告诉SpringMVC 不进行页面跳转,要响应数据 2.返回对象或者集合 *先在spring-mvc中进行处理器适配器配置,然后导入json依赖坐标, 然后函数直接返回对象或者集合,让mvc自动将其转换为json字符串,也要带着@ResponseBody 注解 *在spring-mvc中进行mvc的注解驱动,然后导入json依赖坐标, --->配置更简单 然后函数直接返回对象或者集合,让mvc自动将其转换为json字符串,也要带着@ResponseBody 注解<!--spring mvc 用 json转换器 1个--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.4</version> </dependency><!-- mvc的注解驱动 可以自动加载 处理映射器(requestMappingHandlerMapping),处理适配器(requestMappingHandlerAdapter), 所有这这个配置可以代替 处理映射器和处理适配器的配置 同时, 默认底层会集成 jackson进行对象或者集合的json字符串转换 补:SpringMVC的三大组件 处理映射器(requestMappingHandlerMapping) 处理适配器(requestMappingHandlerAdapter) 视图解析器(InternalResourceViewResolver) --> <mvc:annotation-driven/>
# SpringMVC 获取请求数据
# MVC实现数据请求
基本类型参数
Controller中业务方法的参数名称(形参) 与 请求参数的名称一致,参数值会自动映射匹配。
- 传入的形参 public void param1(String username,String password)
- 访问url /param1?username=凉冰&password=123
Controller中业务方法的参数名称(形参) 与 请求参数的名称不一致,使用@RequestParam注解显示的绑定。
(@RequestParam(value = "name",required = false,defaultValue = "diana") String username) *value: 请求参数名称的别名 *required: 该参数 name 是否必须提供, true为必须提供, 如果没有提供 会报错 *defaultValue: 当没有指定参数时,则使用指定的默认值为参数赋值
POJO类型参数
Controller中业务方法的POJO参数的属性名 与 请求参数的名称一致,参数值会自动映射匹配.
传入的形参 public void param1(User user) User的属性 String username; String password; Address address;--String city; String province;
单个pojo
- 访问url /param2?username=凉冰&password=123
- 输出 //User{username='凉冰', password='123', address=null}
嵌套pojo
访问url /param2?username=凉冰&password=123&address.city=青岛&address.province=山东
输出 //User{username='凉冰', password='123', address=Address{city='青岛', province='山东'}}
数组类型参数(用的不多)
- Controller中业务方法的数组名称 与 请求参数的名称一致,参数值会自动映射匹配
- 传入的形参 public void param3(String[] hobbys)
- 访问url /param3?hobbys=凉冰&hobbys=英雄联盟
- Controller中业务方法的数组名称 与 请求参数的名称一致,参数值会自动映射匹配
集合类型参数
总结
- 集合中存普通参数 --- 使用@RequestParam 去接,也可以用json 数据传,不过没太大意义
- 集合中存json数据 --- 使用@RequestBody 去接 ----springMVC可以直接将json数据转换成对象(需要开启mvc注解驱动)
集合中存储普通参数
参数前加上@RequestParam public void param51(@RequestParam List<String> params)
- 访问url /param51?params=diana¶ms=凉冰
- 输出结果 [diana, 凉冰]
获得集合参数时,要将集合参数包装到一个pojo中。 ----不常用
当使用ajax提交时,可以指定contentType为json形式,这样可以直接用集合接收集合数据(形参前加@RequestBody),无需进行pojo的封装。
(1).axios 提交请求参数 可以将js的参数转换为json类型,这样在请求时不用指定contentType,但是参数users必须是集合类型,具体参照ajax.html js: 键值可以不带引号 json: 键值必须带引号 axios({ method:"POST", url:"http://localhost/SpringMVC_war/param5", data:users }); (2).传入的形参 public void param5(@RequestBody List<User> users) (3).因为要引入js文件,所以必须要开启(静态)资源访问权限 <mvc:resources mapping="/js/**" location="/js/"/> (4).如果要使用html,也要开启(静态)资源访问权限 <mvc:resources mapping="/html/**" location="/html/"/> <!-- 开放资源的访问 (一般是静态资源)--> <!-- <mvc:resources mapping="/js/**" location="/js/"/>--> <!-- <mvc:resources mapping="/img/**" location="/img/"/>--> <!-- <mvc:resources mapping="/html/**" location="/html/"/>--> <!-- 使用原始tomcat 找静态资源 与上面虽然过程不一样,但是功能一样--> <mvc:default-servlet-handler/> (5).在html中导入js文件时,因为不在有两层文件夹,html->ajax.html;js->axios-0.18.0.js <script src="../js/axios-0.18.0.js"></script>
Date类型的参数
默认是 2021/02/02 这种,如果想传入其他类型的时间,需要使用@DateTimeFormat
//接收Date类型的参数 -- 不使用转换器 使用@DateTimeFormat --都可以 @RequestMapping("/date1") @ResponseBody public void test_Date1(Date date1, @DateTimeFormat(pattern = "yyyy-MM-dd") Date date2, @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date3){ // 请求url date1?date1=2021/02/02&date2=2021-04-11&date3=2021-04-11 8:08:08 System.out.println(date1);//Tue Feb 02 00:00:00 CST 2021 System.out.println(date2);//Sun Apr 11 00:00:00 CST 2021 System.out.println(date3);//Sun Apr 11 08:08:08 CST 2021 }
# MVC 获取json数据
使用@RequestBody 传入json数据 由mvc转换成对象——————json数据————重点掌握
User的属性 String username; String password; Address address;--String city; String province;
嵌套pojo
形参列表 public void param22(@RequestBody User user)
json
{ "username":"diana", "password":"123", "address":{ "province":"山东", "city":"青岛" } }输出 User{username='diana', password='123', address=Address{city='青岛', province='山东'}}
集合pojo
形参列表 public void param5(@RequestBody List<User> users)
json数据
- [{"username":"diana","password":"123"}]
[{ "username":"diana", "password":"123", "address":{ "province":"山东", "city":"青岛" }}, { "username":"凉冰", "password":"456", "address":{ "province":"浙江", "city":"杭州" }} ]输出
- [User{username='diana', password='123', address=null}]-- 不分address数据就是null
[User{username='diana', password='123', address=Address{city='青岛', province='山东'}},
User{username='凉冰', password='456', address=Address{city='杭州', province='浙江'}}]
集合普通参数
形参列表 public void param52(@RequestBody List<String> params)
json数据 ["diana","凉冰"]
输出 //[diana, 凉冰]
# MVC获取数据细节
中文乱码问题
在web.xml中配置全局过滤的filter
<!-- 配置全局过滤的filter--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <!-- 解决乱码问题 post --> <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>Restful风格参数获取
- @RequestMapping("/restful/{name}") {}里面是占位符
- 请求url /restful/diana
- @PathVariable(value="name",required = true)String username 使用注解进行占位符的匹配获取
- value的值必须要与{}占位符的值一样
- required设置true 表示必须要这个参数

自定义类型转换器 步骤
定义转换器实现Converter接口
public class DateConverter implements Converter<String, Date> { //将字符串转换成Date // 可以将输入为 /?date=2021-02-02 的字符串 转换为Date类型 public Date convert(String s) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date=null; try { date=simpleDateFormat.parse(s); } catch (ParseException e) { e.printStackTrace(); } return date; } }
在配置文件中声明转换器
<!-- 声明转换器--> <!-- 然后在mvc的注解驱动中声明--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="com.diana.converter.DateConverter"/> </list> </property> </bean>
在<annotation-driven>中引用转换器
<mvc:annotation-driven conversion-service="conversionService"/>
获取Servlet相关API-- 作为形参直接注入即可
*HttpServletRequest *HttpServletResponse *HttpSessionpublic void test_servlet(HttpServletRequest request, HttpServletResponse response, HttpSession session){ System.out.println(request); System.out.println(response); System.out.println(session); }
获取请求头数据
*使用@RequestHeader 相当于 request.getHeader(name) * value 请求头的名称 * required 是否必须携带请求头 *@CookieValue 专门用来获取Cookie的注解 * value 指定cookie的名称 * required 是否必须携带cookie文件上传
文件上传客户端三要素
*type="file" *表单提交方式为 post *表单的enctype属性是多部分表单形式 即 enctype="multipart/form-data"<!-- 单文件上传--> <form action="${pageContext.request.contextPath}/file" method="post" enctype="multipart/form-data"> 名称<input type="text" name="username"><br> 文件<input type="file" name="upload"><br> <input type="submit" value="提交"><br> </form>文件上传步骤
导入fileupload和io坐标
<!-- io--> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <!--fileupload--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency>配置文件上传解析器 spring-mvc
<!-- 配置文件上传解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"/> <property name="maxUploadSize" value="50000"/> <!-- 上传文件总大小--> <property name="maxUploadSizePerFile" value="5000"/> <!-- 上传文件总大小--> </bean>编写文件上传代码
- 单文件上传
名称<input type="text" name="username"><br> 文件<input type="file" name="upload"><br> String username, MultipartFile upload 第一个参数(String)对应第一个name值,第二个参数(MultipartFile 对象)对应第二个name值多文件上传
直接用两个参数进行接收
String username, MultipartFile upload1,MultipartFile upload2使用数组接收
MultipartFile[] uploads -- 同hobbys
# Spring JdbcTemplate 使用
不常用了解即可,后期有mybatis
导入spring-jdbc,spring-tx坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.3.6</version> </dependency>创建数据库和实体
创建jdbcTemplate对象,或者让spring帮我们创建对象
<!--加载外部配置文件property--> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- el表达式 来获取配置文件信息--> <bean id="dataSource_c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="jdbcUrl" value="${jdbc.url}"/> </bean> <!-- 在spring 容器中产生 jdbc模板对象 同时注入数据源--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource_c3p0"/> </bean>执行数据库操作
@Test//删除 public void testDelete(){ //增删改 都是 update方法 里面语句不一样而已 int row = jdbcTemplate.update("delete from account where name=?", "diana"); System.out.println(row); } @Test//查询全部 public void testQueryAll(){ List<User> users = jdbcTemplate.query("select * from user", new BeanPropertyRowMapper<User>(User.class)); System.out.println(users); } @Test//查询单个 public void testQueryOne(){//Bean 类型封装 User user = jdbcTemplate.queryForObject("select * from user where username=?", new BeanPropertyRowMapper<User>(User.class),"凉冰"); System.out.println(user); } @Test//聚合查询 public void testQueryCount(){//简单类型 int count = jdbcTemplate.queryForObject("select count(*) from user",int.class); System.out.println(count); }
# SpinrgMVC拦截器
这里的异常处理是xml完成的
生成拦截类,实现HandlerInterceptor接口(有三个方法)。
public class MyInterceptor2 implements HandlerInterceptor { //在目标方法执行之前 执行 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("要执行方法了~~~~222"); return true; } //在目标方法执行之后 视图对象返回之前执行 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("执行完方法了,要跳转到视图对象了!!222"); modelAndView.addObject("user1","凉冰");//将user1的参数由diana改成了凉冰 } //在所有流程执行完毕后 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("全部执行完了!!!222"); } }配置拦截器。
<!-- 配置拦截器--> <mvc:interceptors> <!--拦截器1--> <mvc:interceptor> <!--对哪些资源进行拦截 /** 表示拦截所有--> <mvc:mapping path="/**"/> <bean class="com.diana.interceptor.MyInterceptor1"/> </mvc:interceptor> <!--拦截器2--> <mvc:interceptor> <!--对哪些资源进行拦截--> <mvc:mapping path="/**"/> <bean class="com.diana.interceptor.MyInterceptor2"/> </mvc:interceptor> </mvc:interceptors> ---拦截器链的执行顺序---- 要执行方法了~~~~ 要执行方法了~~~~222 目标方法正在执行!! 执行完方法了,要跳转到视图对象了!!222 执行完方法了,要跳转到视图对象了!! 全部执行完了!!!222 全部执行完了!!!编写方法并进行测试。
# SpringMVC异常处理
这里的异常处理是xml完成的
instanceof的用法instanceof 是 Java 的一个二元操作符,类似于 ==,>,< 等操作符。 instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。
异常处理的两种方法
使用SpringMVC提供的简单异常处理器
SimpleMappingExceptionResolver<!-- 配置简单映射异常处理器--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 默认错误视图 value 是视图名称(自己随便起名) 省略了前后缀--> <property name="defaultErrorView" value="/exception/error"/> <!-- 异常错误映射 优先判断里面的异常类型,里面没有时 才会进入默认错误视图--> <property name="exceptionMappings"> <map> <entry key="com.diana.exception.MyException" value="/exception/Myerror"/><!-- 自定义异常--> <entry key="java.lang.ClassCastException" value="/exception/error_class"/><!-- 类型转换异常--> </map> </property> </bean>实现Spring的异常处理接口
HandlerExceptionResolver自定义自己的异常处理器
创建异常处理类实现 接口 HandlerExceptionResolver
public class MyExceptionResolver implements HandlerExceptionResolver { /* 参数 Exception e :异常对象 返回值 ModelAndView : 跳转到错误视图信息 */ public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView modelAndView=new ModelAndView(); //instanceof 是 Java 的一个二元操作符,类似于 ==,>,< 等操作符。 //instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。 if(e instanceof MyException){ //执行异常相应的操作 modelAndView.addObject("info","自定义异常"); //modelAndView.setViewName("/exception/Myerror"); //跳到自己的页面 }else if(e instanceof ClassCastException){ //执行异常相应的操作 modelAndView.addObject("info","类转换异常"); //modelAndView.setViewName("/exception/error_class");//跳到自己的页面 }else{ //执行异常相应的操作 modelAndView.addObject("info","默认类型异常"); //modelAndView.setViewName("/exception/error");//跳到自己的页面 } modelAndView.setViewName("/exception/error"); //都跳转error页面 return modelAndView; } }配置异常处理器
<!-- 配置自定义异常处理器--> <bean class="com.diana.resolver.MyExceptionResolver"/>编写异常页面
测试异常跳转
- 在编写代码时,遇到异常就往外抛,只在最后同一对异常进行处理。
