文章目录
SpringMVC
一、概述
1.1 三层架构
开发框架一般基于两种形式,一种为C/S架构,即客户端/服务器;另一种为B/S架构,即浏览器服务器架构。在JavaEE开发中,几乎都是B/S架构。B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。
- 表现层:即Web层,它负责接收客户端请求,向客户端响应结果,通常客户端使用HTTP协议请求web层,web需要接收HTTP请求,完成HTTP响应。表现成包括展示层和控制层,控制层负责接收请求,展示层负责结果的展示,表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。表现层的设计一般都使用MVC模型
- 业务层:即service层。它负责业务逻辑处理,和我们开发项目的需求相关。web层依赖业务层,但是业务层不依赖web层。业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务的一致性,即事务应该放在业务层控制
- 持久层:即dao层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。持久层就是和数据库交互,对数据库表进行增删改查
1.2 MVC
MVC即Model View Controller,是模型—视图—控制器的缩写,是一种用于设计创建Web应用程序表现层的模型
- Model:通常指的是我们的数据模型。作用一般用于封装数据
- View:通常指jsp或html,作用一般是展示数据,通常视图依据模型数据创建
- Controller:应用程序中处理用户交互的部分,作用一般是处理程序的逻辑
1.3 SpringMVC
- SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring FrameWork的后续产品。已经融合在Spring Web Flow里面。Spring框架提供了构建Web应用程序的全功能MVC模型。使用Spring可插入的MVC架构,从而在使用Spring进行WEB开发时,可以选择Spring的SpringMVC框架或其它MVC开发框架,如Strusts1,Struts2等
- SpringMVC是目前主流的MVC框架之一,并且随着Spring3.0的发布,全面超越Struts2,称为最优秀的MVC框架
- 它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无需实现任何接口
二、入门案例
2.1 环境搭建
-
依赖
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <!--版本锁定--> <spring.version>5.2.5.RELEASE</spring.version> </properties> <dependencies> <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>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> <scope>provided</scope> </dependency> </dependencies>
-
Web.xml
<!--前端控制器配置--> <servlet> <servlet-name>dispatcherServlet</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>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
SpringMVC.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" 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.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="ysw.controller"></context:component-scan> <!--视图解析器--> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--文件所在目录--> <property name="prefix" value="/WEB-INF/pages/"/> <!--文件后缀名--> <property name="suffix" value=".jsp"/> </bean> <!--开启SpringMVC框架注解支持--> <mvc:annotation-driven/> </beans>
2.2 工作流程
三、RequestMapping注解
- 出现的位置:
- 类上:代表请求URL的第一级目录,若不写就相当于服务的根目录
- 方法上:请求URL的第二级访问目录
- 属性:
- value:用于指定请求的URL。和Path属性的作用一样
- method:用于指定请求方式
- params:用于指定限制请求参数的条件。支持简单表达式。要求请求参数的key和value必须和配置一样
- header:用于指定限制请求消息头的条件
四、请求参数的绑定
4.1 参数传递
-
将参数的值赋给相应的属性
- 可以在表单的name属性中填写相对应的属性名
-
将参数封装到对象
- 在表单的name属性中填写对象.属性名
-
将参数封装到集合
- 在表达name属性中填写集合.属性
-
代码演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>param</title> </head> <body> <a href="param/testParam?username=hehe&password=123">请求参数绑定测试</a> <form action="/param/saveAccount" method="post"> <%--将参数值传递给相应属性--%> 姓名:<input type="text" name="username"><br> 密码:<input type="text" name="password"><br> 金额:<input type="text" name="money"><br> <%--将参数封装到对象--%> 用户姓名:<input type="text" name="user.name"><br> 用户年龄:<input type="text" name="user.age"><br> <input type="submit" value="提交"> </form> <form action="/param/saveAccount" method="post"> 姓名:<input type="text" name="username"><br> 密码:<input type="text" name="password"><br> 金额:<input type="text" name="money"><br> <%--将参数封装到集合--%> 用户姓名:<input type="text" name="list[0].name"><br> 用户年龄:<input type="text" name="list[0].age"><br> 用户姓名:<input type="text" name="map['one'].name"><br> 用户年龄:<input type="text" name="map['one'].age"><br> <input type="submit" value="提交"> </form> </body> </html>
4.2 自定义类型转换
public class StringToDate implements Converter<String, Date> {
@Override
public Date convert(String s) {
if (s == null) {
throw new RuntimeException("传入参数错误!!");
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
return simpleDateFormat.parse(s);
} catch (ParseException e) {
throw new RuntimeException("格式转换错误!!");
}
}
}
-
配置文件
<!--配置自定义类型转换器--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="ysw.Utils.StringToDate"/> </set> </property> </bean> <!--开启SpringMVC框架注解支持--> <mvc:annotation-driven conversion-service="conversionService"/>
五、常用注解
-
RequestParam
- 作用:将请求中指定名称的参数给控制器中的形参赋值
- 属性:value:请求参数中的名称;required:请求参数中必须提供此参数。默认值为True。表示必须提供
-
RequestBody
- 作用:获取请求体中的内容,直接使用会得到key=value
- 属性:required:是否必须有请求体。默认为true。当取值为true时get请求会报错。如果取值为false,get请求得到null
-
PathVariable
- 作用:拥有绑定url中的占位符。例如“rul中有/delete/{id},{id}就是占位符
- 属性:value:指定url中的占位符名称
- rest父类风格的URL优点:
- 结构清晰
- 符合标准
- 易于理解
- 扩展方便
-
RequestHeader
- 获取请求头的值
-
CookieValue
- 获取Cookie的值
-
ModelAttribute
- 可以用于修饰方法和参数
- 出现在方法上,表示当前方法会在控制器的方法执行前先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法
- 出现在参数上,获取指定的数据给参数赋值
-
SessionAttributes
- 用于多次执行控制器方法间的参数共享
- 属性:value:用于指定存入的属性名称;type:用于指定存入的数据类型
- 作用在类上
@SessionAttributes(value = {"msg"}) @Controller @RequestMapping("/param") public class ParamController { @RequestMapping("/testSessionAttributes") public String testSessionAttributes(Model model){ model.addAttribute("msg","hello"); return "success"; } }
六、响应数据和结果视图
6.1 字符串
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testString")
public String testString(Model model){
System.out.println("testString!!!");
User user = new User();
user.setName("Tom");
user.setPassword("1234");
user.setAge(18);
model.addAttribute("user",user);
return "success";
}
}
- 在页面可以通过${user.name}获取到值
6.2 void
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("testVoid!!!");
//转发
// request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
//重定向
// response.sendRedirect(request.getContextPath()+"/index.jsp");
//向页面输出数据
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
response.getWriter().print("你好!!");
return;
}
}
6.3 ModelAndView
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
ModelAndView modelAndView = new ModelAndView();
User user = new User();
user.setAge(19);
user.setPassword("1234");
user.setName("Job");
modelAndView.addObject("user", user);
//指定跳转到某个页面
modelAndView.setViewName("success");
return modelAndView;
}
}
七、转发和重定向
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/forwardOrRedirect")
public String forwardOrRedirect() {
System.out.println("转发或重定向!!");
//转发
//return "forward:/WEB-INF/pages/success.jsp";
//重定向
return "redirect:/index.jsp";
}
}
八、ResponseBody响应json数据
-
首先需要配置哪些静态资源不需要被控制器拦截(springmvc.xml)
<!--告诉前端控制器哪些资源不需要拦截--> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/images/**" location="/images/"/> <mvc:resources mapping="/js/**" location="/js/"/>
-
导入Jar包
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.10.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.10.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.3</version> </dependency>
-
测试类
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/testAjax") @ResponseBody public User testAjax(@RequestBody User user) { System.out.println("testAjax执行!!!"); //客户端发送Ajax的请求,传json字符串,后端将json字符串封装到User对象中 System.out.println(user.toString()); user.setName("Lily"); user.setAge(30); //返回json数据 return user; } }
九、文件上传
9.1 普通文件上传
-
借助第三方组件上传文件,导入依赖
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>commist</artifactId> <version>1.0.0</version> </dependency>
-
SpringMVC上传文件,配置文件解析器(springmvc.xml)
<!--文件解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--允许上传的最大文件大小--> <property name="maxUploadSize" value="10485760"/> </bean>
-
测试
@Controller @RequestMapping("/user") public class UserController { /** * @Param [req, upload] * @return java.lang.String * @Date 9:03 2020/7/4 * @Description: //TODO **/ @RequestMapping("/fileupload1") public String fileupload1(HttpServletRequest req, MultipartFile upload) throws IOException { System.out.println("文件上传!!"); String path = req.getSession().getServletContext().getRealPath("/uploads/"); File file = new File(path); if (!file.exists()) { //创建文件夹 file.mkdirs(); } //获取文件名称 String filename = upload.getOriginalFilename(); //将文件名称设置为唯一值 String replace = UUID.randomUUID().toString().replace("-", ""); filename = replace + "_" + filename; //完成文件上传 upload.transferTo(new File(path, filename)); return "success"; } }
9.2 分服务器上传文件
-
导入jar包
<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.19.4</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <version>1.19.4</version> </dependency>
-
代码演示
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/fileupload") public String fileupload2(MultipartFile upload) throws IOException { System.out.println("文件上传!!"); //定义上传文件服务路径 String path = "http://localhost:xxxx/xxxx/"; //获取文件名称 String filename = upload.getOriginalFilename(); //将文件名称设置为唯一值 String replace = UUID.randomUUID().toString().replace("-", ""); filename = replace + "_" + filename; //创建客户端对象 Client client = Client.create(); //和文件服务器进行连接 WebResource resource = client.resource(path + filename); //上传文件 resource.put(upload.getBytes()); return "success"; } }
十、SpringMVC异常处理
- 异常测试
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testException")
public String testException() throws SysException {
try {
//模拟异常
int a = 10 / 0;
} catch (Exception e) {
//打印异常信息
e.printStackTrace();
//抛出自定义异常
throw new SysException("出现错误!!!");
}
return "success";
}
}
- 自定义异常
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* @return org.springframework.web.servlet.ModelAndView
* @Param [httpServletRequest, httpServletResponse, o, e]
* @Date 9:48 2020/7/4
* @Description: 处理异常
**/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
//获取异常对象
SysException ex = null;
if (e instanceof SysException) {
ex = (SysException) e;
} else {
ex = new SysException("系统正在维护……");
}
//创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("errorMsg", ex.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
- 配置异常处理器
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="ysw.exception.SysExceptionResolver"/>
十一、SpringMVC中的拦截器
-
自定义类实现HandlerInterceptor接口
/** * @Description: TODO * @Author YunShuaiWei * @Date 2020/7/4 10:46 * @Version **/ public class MyInterceptor implements HandlerInterceptor { /** * @return boolean * true:放行,执行下一个拦截器,若没有,则执行controller中的方法 * false:不放行 * @Param [request, response, handler] * @Date 10:47 2020/7/4 * @Description: 预处理,controller方法执行前 **/ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("……"); return true; } /** * @return void * @Param [request, response, handler, modelAndView] * @Date 10:58 2020/7/4 * @Description: Controller执行后执行的方法 **/ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle……"); request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request, response); } /** * @return void * @Param [request, response, handler, ex] * @Date 10:59 2020/7/4 * @Description: 最后执行的方法, 即跳转到success.jsp之后会执行该方法 **/ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion……"); } }
-
配置拦截器
<!--配置拦截器--> <mvc:interceptors> <mvc:interceptor> <!--要拦截的具体方法--> <mvc:mapping path="/user/*"/> <!--不要拦截的方法 <mvc:exclude-mapping path=""/>--> <bean class="ysw.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>