Spring+SpringMVC+Mybatis入门(一)+https://developer.aliyun.com/article/1390490?spm=a2c6h.13148508.setting.15.25714f0eSQX4kb
二、SpringMVC
1、MVC思想二、SpringMVC
模型-视图-控制器(MVC)是一个以设计页面应用程序为基础的设计思想。它主要通过分离模型、试图及控制器在应用程序的角色将业务逻辑从界面中解耦。通常模型负责封装应用程序数据在视图层展示。视图仅仅只是展示这些数据,不包含任何业务逻辑。控制器负责接收来自用户的请求,并调用后台服务(service或者dao)来处理业务逻辑。处理后,后台业务层可能会返回了一些数据在视图层展示。控制器收集这些数据以及准备模型在视图层展示。MVC模式的核心思想是将业务逻辑从界面中抽离出来,允许他们单独改变而不会相互影响。
2、SpringMVC概念和特点
是一个基于请求驱动的Web框架
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="cn.ken.controller"/> <!-- 开启注解驱动 --> <mvc:annotation-driven/> <!-- 使用默认的servlet来响应静态文件 --> <mvc:default-servlet-handler/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前缀:在WEB-INF目录下的jsp目录下 --> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
web.xml
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!-- 编码过滤 --> <filter> <filter-name>encodingFilter</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>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- servlet请求分发器,中央处理器 --> <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:servlet-context.xml</param-value> </init-param> <!-- 表示启动容器时初始化该Servlet,否则是调用时初始化 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <!-- 这是拦截请求,“/”表示拦截所有请求,“*.do”表示拦截所有.do请求 --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
EL表达式失效 这个问题是由于 版本 太高导致的,在 JSP2.0 时,增加了 EL 语言,我们可以通过 EL 语言,实现获取数据,进一步将 Servlet 的代码从 JSP 页面中分离出来。而 EL 语言给大家带来了方便。但有时也会遇到 EL 表达式不能显示的情况。 在 2.0 到 2.4 版本它是默认支持 EL 表达式的,如果使用 2.5 版本,默认 EL 表达式是关闭的,我们需要开启才可以使用。 解决方法: 换成 2.0 ~ 2.4 之间的版本或在页面中加入<%@ page isELIgnored=“false” %>
3、请求转发
/** * 重定向与请求转发 * SpringMVC内部默认采用请求转发形式 * 请求转发 * 地址栏不发生改变,以forward: 开头 * 方法有两种返回值 * 1、返回ModelAndView对象 * 2、返回视图名称字符串 * 注:默认都会从视图解析器设置的路径下查找指定视图(不需要设置视图后缀,直接写视图名),如果想从项目的根目录(如果有类路径,则从类路径)查找,则使用forward: * 重定向 * 地址栏会发生改变,以redirect: 开头 */ @Controller @RequestMapping("user") public class UserController { @RequestMapping("view") public ModelAndView hello(@RequestParam(name = "uid", defaultValue = "11")Integer id){ ModelAndView modelAndView = new ModelAndView(); //设置数据模型 modelAndView.addObject("key","value"); //设置试图 modelAndView.setViewName("hello"); System.out.println(id); return modelAndView; } @RequestMapping("view1") public String view1(){ return "forward:/WEB-INF/jsp/view1.jsp"; } //转发至控制器需加forward,不用forward被视图解析器加前后缀则无法转发到控制器 @RequestMapping("view2") public String view2(){ return "forward:view?uid=222"; } }
<%-- Created by IntelliJ IDEA. User: Ken-Chy Date: 2022/2/23 Time: 22:45 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page isELIgnored="false" %> <html> <head> <title>Title</title> </head> <body> <h2>${key}<br>${msg}<br>${param.uid}</h2> <!--param可以获得url中的参数--> </body> </html>
4、重定向
重定向是发一个302状态码给浏览器,浏览器自己去请求跳转的网页,地址栏也会发生改变
/** * 重定向: * 默认从项目的根目录下查找资源(如果类设置了路径,则从类路径即user开始查找) * @param session * @return */ @RequestMapping("view3") public String view3(HttpSession session){ //因为重定向是两次请求,故通过HttpServletRequest设置的值无法在重定向后使用,需要使用session设置值 session.setAttribute("msg","11211222"); return "redirect:view"; } /** * 重定向可以传递参数,如果直接传递中文,则无法获取(因为浏览器会将中文参数进行unicode编码) * 故需要使用RedirectAttributes对象设置 * @param attributes * @return */ @RequestMapping("view4") public String view4(RedirectAttributes attributes){ //通过此种方法会自动在重定向时拼接上参数 attributes.addAttribute("name","张三"); //不需要自己在下面路径后用问号加参数 return "redirect:/view111.jsp"; }
5、设置请求域
- 使用ModelAndView对象设置
- addObject(“名”,“值”)
- 使用HttpServletRequest对象设置
- setAttribute(“名”,“值”)
- 使用Model对象设置
- addAttribute(“名”,“值”)
- 使用ModelMap对象设置
- addAttribute(“名”,“值”)
- 使用Map对象设置
- put(“名”,“值”)
6、Json数据开发
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.11.4</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.11.4</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.4</version> </dependency>
<!-- 开启注解驱动 --> <mvc:annotation-driven> <!-- mvc 请求映射 处理器与适配器配置 --> <!-- 用于将返回值转换为json --> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean> </mvc:message-converters> </mvc:annotation-driven>
/** * Json数据开发 * @ResponseBody: * 设置在方法级别或者方法的类型前 * 默认控制器中方法的返回值是会去找对应的视图页面,如果想要返回数据,需要将返回的结果转换成字符串响应(加上JsonConverter * 则转换成json字符串) * @RequestBody: * 设置在形参前 * 要求传递的参数是一个Json格式的字符串(字符串!!!) */ @Controller @RequestMapping("json") public class JsonController { @RequestMapping("json1") @ResponseBody public User json(){ User user = new User("xxx","ssss"); return user; } @RequestMapping("json2") @ResponseBody public User json2(User user){ return user; } }
<html> <body> <h2>Hello World!</h2> </body> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $.ajax({ type:"get", url:"json/json2", // 此data是发送到服务器的数据 data:{ "name":"admin", "password":"129496" }, //此data是服务器的返回数据 success:function (data){ console.log(data) } }) </script> </html>
7、拦截器实现
<!-- 拦截器配置:方式一 --> <mvc:interceptors> <!-- 使用bean定义一个Interceptor,拦截所有请求 --> <bean class="cn.ken.MyInterceptor"></bean> </mvc:interceptors> <!-- 拦截器配置:方式二(推荐使用) --> <mvc:interceptors> <!-- 定义在mvc:interceptor下面,可以自定义拦截请求,如果有多个拦截器满足拦截处理的要求,则依据配置的先后顺序来执行 --> <mvc:interceptor> <!-- 通过mvc:mapping配置需要拦截的资源,支持通配符,可以配置多个 --> <mvc:mapping path="/**"/> <!--"/**"表示拦截所有的请求--> <!-- 配置不需要拦截的资源,支持通配符,可以配置多个 --> <mvc:exclude-mapping path="/json/*"/><!--放行json下的路径,即不会经过拦截器处理--> <bean class="cn.ken.MyInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> </beans>
实现方法一:实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor { //在目标方法(Handler)执行之前执行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("11"); return true; } //在目标方法实行之后,视图生成之前 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("22"); } //在视图生成之后执行 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("33"); } }
实现方法二:继承HandlerInterceptorAdapter类
如果多个拦截器同时生效,则先配置的先执行
先配置的拦截其中对应的preHandle方法限制性,postHandle和afterCompletion后执行
8、文件上传
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.2</version> </dependency>
<!-- 文件上传 --> <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"> <!-- 允许文件上传的最大尺寸 --> <property name="maxUploadSize"> <value>104857600</value> </property> <!-- 将文件放入临时文件夹的最大大小限制,此值是阈值,如果大于则在硬盘生成临时文件,否则存在内存 --> <property name="maxInMemorySize"> <value>4096</value> </property> </bean>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%-- 文件上传表单: 表单的提交方式:post 表单的类型:普通表单,二进制表单(enctype="multipart/form-data") 设置文件域的name属性值 --%> <form method="post" action="upload" enctype="multipart/form-data"> 文件:<input name="myfile" type="file"> <button>上传</button> </form> </body> </html>
@Controller public class UploadController { /** * 文件上传 * 在形参上使用@RequestParam("myfile")MultipartFile file接收上传的文件 * 其中myfile代表的是表单元素的name属性值 */ @RequestMapping("upload") public String upload(HttpServletRequest request, @RequestParam("myfile")MultipartFile file){ if (file.isEmpty()){ request.setAttribute("msg","请上传文件"); return "result"; } //得到上传的文件名 String name = file.getOriginalFilename(); //截取文件名获得后缀 String siffx = name.substring(name.lastIndexOf(".")); //生成随机文件名 String filename = System.currentTimeMillis() + siffx; //得到项目的真实路径 String realPath = request.getServletContext().getRealPath("/"); //设置文件的存放路径 File filePath = new File(realPath+"/upload"); //判断文件是否存在 if (!filePath.exists()){ filePath.mkdir(); } try { file.transferTo(new File(filePath, filename)); request.setAttribute("msg","文件上传成功"); } catch (IOException e){ request.setAttribute("msg","文件上传失败"); e.printStackTrace(); } return "result"; } }
9、RESTFUL URL设计风格
Restful风格的API是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件,基于这个设计风格设计的软件可以更简洁、更有层次,更易于实现缓存等机制
在Restful风格中,用户请求的url使用同一个url,请求方式采用get、post、delete、put等方式对请求的处理方法进行分类,这样可以在前后台分离式的开发中使得前端开发人员不会对请求的资源地址产生混淆和大量额检查方法名的麻烦,形成一个统一的接口
@Controller public class UploadController { /** * 文件上传 * 在形参上使用@RequestParam("myfile")MultipartFile file接收上传的文件 * 其中myfile代表的是表单元素的name属性值 */ @RequestMapping("upload") public String upload(HttpServletRequest request, @RequestParam("myfile")MultipartFile file){ if (file.isEmpty()){ request.setAttribute("msg","请上传文件"); return "result"; } //得到上传的文件名 String name = file.getOriginalFilename(); //截取文件名获得后缀 String siffx = name.substring(name.lastIndexOf(".")); //生成随机文件名 String filename = System.currentTimeMillis() + siffx; //得到项目的真实路径 String realPath = request.getServletContext().getRealPath("/"); //设置文件的存放路径 File filePath = new File(realPath+"/upload"); //判断文件是否存在 if (!filePath.exists()){ filePath.mkdir(); } try { file.transferTo(new File(filePath, filename)); request.setAttribute("msg","文件上传成功"); } catch (IOException e){ request.setAttribute("msg","文件上传失败"); e.printStackTrace(); } return "result"; } }
10、全局异常统一处理
使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver
使用简单,集成简单,扩展性好,对代码没有入侵性(即改变原来代码)
但仅能获取到异常信息,若在出现异常时,对需要获取异常以外的数据的情况不适用
@Service public class UserServiceImpl implements UserService { @Override public int addUser(User user) { // int i = 1/0; //-->error页面 if(false){ throw new BusinessException(); } return 0; }
public class BusinessException extends RuntimeException { private Integer code=400; private String msg="业务异常"; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 异常发生时设置默认的异常处理页面(error是一个视图名) --> <property name="defaultErrorView" value="error"/> <!-- 异常发生时,设置异常的变量名 --> <property name="exceptionAttribute" value="ex"/> <!-- 设定自定义异常与页面的映射 --> <property name="exceptionMappings"> <props> <!-- key:自定义异常对象的路径,标签中设置具体的处理页面的视图名 --> <prop key="cn.ken.exception.BusinessException">buss_error</prop> </props> </property> </bean>
实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器(推荐使用)
具有集成简单,有良好的扩展性,对代码没有入侵性
在异常处理时可以获取导致异常出现的对象,有利于提供更详细的异常处理信息
@Component public class GlobalExceptionResolver implements HandlerExceptionResolver { /** * * @param request * @param response * @param handler 目标方法 * @param ex 异常对象 * @return */ @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView modelAndView = new ModelAndView("error"); modelAndView.addObject("ex","默认的异常信息"); /* * 根据不同的异常执行不同的处理 */ if (ex instanceof BusinessException){ BusinessException b = (BusinessException) ex; b.setCode(500); b.setMsg("这是业务异常"); modelAndView.setViewName("buss_error"); modelAndView.addObject("e",b); return modelAndView; } return modelAndView; } }
使用@ExceptionHandler注解实现异常处理
具有集成简单,扩展性好(只需将需要异常处理的Controller类继承BaseController即可)不需要附加Spring配置等
但该方法对代码存在入侵性(需要修改已有代码,使相关类继承BaseController),在处理异常时不能获取除异常以外的数据
ublic class BaseController { @ExceptionHandler public String exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e){ request.setAttribute("ex","这是第三种异常处理"); if(e instanceof BusinessException){ return "buss_error"; } return "error"; } }
public class AccountController extends BaseController{ }
未捕获异常处理
在web.xml中通过结点配置特定异常情况的显示页面
<error-page> <!-- 如果出现404异常,则跳转到项目根路径下的404.jsp页面 --> <error-code>404</error-code> <location>/404.jsp</location> </error-page> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/500.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page>
Spring+SpringMVC+Mybatis入门(三)+https://developer.aliyun.com/article/1390539?spm=a2c6h.13148508.setting.15.28964f0eDxD8Uj