author:空巷
WeChat Applet :Java空巷
QQ: 2399014502
Mail: [email protected]
WeiBo : KongXiang_
WeChat:
推荐学习路径:http://c.biancheng.net/spring_mvc/
MVC 设计不仅限于 Java Web 应用,还包括许多应用,比如前端、PHP、.NET 等语言。之所以那么做的根本原因在于解耦各个模块。
MVC 是 Model、View 和 Controller 的缩写,分别代表 Web 应用程序中的 3 种职责。
基于 Servlet 的 MVC 模式的具体实现如下。
Spring MVC 框架主要由 DispatcherServlet、处理器映射、控制器、视图解析器、视图组成,其工作原理如图 所示。
从图 可总结出 Spring MVC 的工作流程如下:
传统的模型层被拆分为了业务层(Service)和数据访问层(DAO,Data Access Object)。 在 Service 下可以通过
Spring 的声明式事务操作数据访问层,而在业务层上还允许我们访问 NoSQL ,这样就能够满足异军突起的NoSQL 的使用了,它可以大大提高互联网系统的性能。
特点: 结构松散,几乎可以在 Spring MVC 中使用各类视图 松耦合,各个模块分离 与 Spring 无缝集成
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>springmvc-studyartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.12version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.9version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>6.1.5.Finalversion>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.1version>
<configuration>
<source>${java.version}source>
<target>${java.version}target>
<encoding>${project.build.sourceEncoding}encoding>
configuration>
plugin>
plugins>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
project>
在web工程下配置DispatcherServlet的servlet
<servlet>
<servlet-name>spring-mvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>spring-mvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
在springMvc中,视图都放在WEB-INF中以保证视图安全。客户端必须通过访问servlet才能跳转到WEB-INF
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/" />
<property name="suffix" value=".jsp" />
bean>
beans>
编写一个Controller,继承Controller接口
public class FirstController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws Exception {
//ModelAndView 封装了模型和视图
ModelAndView mv = new ModelAndView();
//模型里封装数据
mv.addObject("HelloMvc","Hello springMVC!");
//封装跳转的视图
mv.setViewName("HelloMvc");
//不是有个视图解析器吗
//这玩意就是为了省事的,自动给你加个前缀后缀
//就成了 /jsp/hellomvc.jsp 不就是拼串吗
return mv;
}
}
spingMvc默认去找WEB-INF下的spring-mvc-servlet.xml ,要创建一个spring-mvc-servlet.xml 文件
<bean id="/hellomvc" class="com.xinzhi.controller.FirstController"/>
注解就要扫包
<context:component-scan base-package="com.xinzhi"/>
<mvc:default-servlet-handler />
<mvc:annotation-driven />
@Controller//说明是Controller层
@RequestMapping("/user/") //路径
public class UserController {
//一个主路径可以有多个子路径,多个功能可以由一个servlet来处理
@RequestMapping("login")
public String login(Model model) {
model.addAttribute("ogin","denlu!");
return "Login";
}
@RequestMapping("register")
public String register(Model model) {
model.addAttribute("egister","zhuce!");
return "Register";
}
}
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,在将结果返回给请求者。
简要分析执行流程
DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
如上url拆分成三部分:
http://localhost:8080服务器域名
SpringMVC部署在服务器上的web站点
hello表示控制器
通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。
HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
Handler让具体的Controller执行。
Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
视图解析器将解析的逻辑视图名传给DispatcherServlet。
DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
最终视图呈现给用户。
之前返回的是模型加视图,耦合性太高,有时候不需要跳转视图也会强行跳转使用Model参数
Spring 视图解析器是 Spring MVC 中的重要组成部分,用户可以在配置文件中定义 Spring MVC 的一个视图解析器(ViewResolver),示例代码如下:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/" />
<property name="suffix" value=".jsp" />
bean>
看代码
@RequestMapping(value = "login")
public String login(Model model) {
model.addAttribute("ogin","登录!");
return "Login";
}
//视图解析器将会自动添加前缀和后缀。
这个注解很强大,可以放在方法上也可以放在类上,放在类上所有方法都默认加上该注解有六个参数
例如:
@RequestMapping(value = "login",method = RequestMethod.POST)
public String login(Model model, User user) {
System.out.println(user.getUsername());
System.out.println(user.getId());
System.out.println(user.getPassword());l
model.addAttribute("login","登录!");
return "Login";
}
好处:
在 web.xml 中配置一个字符集过滤器即可
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
建个首页
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
没注册的用户,请 注册!
已注册的用户,去 登录!
建个实体类
package pojo;
public class UserForm {
private String uname; // 与请求参数名称相同
private String upass;
private String reupass;
// 省略getter和setter方法
}
不需要一个个的getParameter(),要什么直接拿
通过 @RequestParam 接收请求参数
通过 @RequestParam 接收请求参数适用于 get 和 post 提交请求方式,可以将“通过实体 Bean 接收请求参数”部分控制器类 UserController 中 register 方法
@RequestMapping("/register")
/**
* 通过@RequestParam接收请求参数
*/
public String register(@RequestParam String uname,
@RequestParam String upass, Model model) {
if ("zhangsan".equals(uname) && "123456".equals(upass)) {
logger.info("成功");
return "login"; // 注册成功,跳转到 login.jsp
} else {
// 在register.jsp页面上可以使用EL表达式取出model的uname值
model.addAttribute("uname", uname);
return "register"; // 返回 register.jsp
}
}
@RequestMapping(value = "login",method = RequestMethod.POST)
public String login(Model model, User user) {
System.out.println(user.getUsername());
System.out.println(user.getId());
System.out.println(user.getPassword());l
model.addAttribute("login","登录!");
return "Login";
}
通过 @PathVariable 接收 URL 中的请求参数
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/user")
// 必须节method属性
/**
* 通过@PathVariable获取URL的参数
*/
public String register(@PathVariable String uname,@PathVariable String upass,Model model) {
if ("zhangsan".equals(uname)
&& "123456".equals(upass)) {
logger.info("成功");
return "login"; // 注册成功,跳转到 login.jsp
} else {
// 在register.jsp页面上可以使用EL表达式取出model的uname值
model.addAttribute("uname", uname);
return "register"; // 返回 register.jsp
}
}
}
但参数多了这么传是不是很啰嗦。更牛逼了 直接传个对象
@RequestMapping(value = "login",method = RequestMethod.POST)
public String login(Model model, User user) {
System.out.println(user.getUsername());
System.out.println(user.getId());
System.out.println(user.getPassword());l
model.addAttribute("login","登录!");
return "Login";
}
这里介绍了几种常用的传参方式,还有很多,可以自行去学习。
可以使用fastjson
导入依赖
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.68version>
dependency>
@RequestMapping(value = "getUsers",produces = {"text/json;charset=utf-8"})
@ResponseBody
public String getUsers(){
List<User> users = new ArrayList<User>(){{
add(new User("wangwu","2222",23));
add(new User("空巷","333",23));
}};
return JSONArray.toJSONString(users);
}
@ResponseBody能将处理的结果放在响应体中,直接返回,不走视图解析器
每次都需要自己处理数据麻烦 那么springMVC 封装了一个更好用的 只需要在配置文件中注入一个消息转换器
<mvc:annotation-driven >
<mvc:message-converters>
<bean id="fastjson"
class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8value>
<value>application/json;charset=UTF-8value>
list>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
@RequestMapping("set")
//直接将返回值以数据的形式返回到响应体
@ResponseBody
public User set(@Validated User user, BindingResult br) {
List<ObjectError> allErrors = br.getAllErrors();
for (ObjectError allError : allErrors) {
System.out.println(allError.getCode()+"---"+allError.getDefaultMessage());
}
System.out.println(user.getId());
return user;
}
Spring MVC 提供了几个内置的格式化转换器,具体如下。
@DateTimeFormat(pattern = "yyyy-mm-dd")
private Date birthday;
@NumberFormat(pattern = "#,###,###.#")
private Double salary;
@NotNull 对象不为空
@AssertTrue Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
@Size(min =, max =) 长度是否在给定的范围
@Min(value=) 验证 Number 对象是否大等于指定的值
@Max(value=) 验证 Number 对象是否小等于指定的值
@Pattern 验证 String 对象是否符合正则表达式的规则
@Past @Future验证 Date 和 Calendar 时间对象是否在当前时间之前/之后
@Email 是否是正确的邮箱地址
需要引入jar
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>5.1.1.Finalversion>
dependency>
在 springmvc.xml 中注册 hibernate 的校验器,并在原来的 mvc 注解驱动中设置 validator 属性:
<mvc:annotation-driven validator="validator" />
property>
bean>
java:
@Max(value = 20L,message = "id不能大于20")
private int id;
@NotNull(message = "名字不能为空")
private String username;
@Null
private String password;
@RequestMapping("set")
@ResponseBody
//用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。
public User set(@Validated User user, BindingResult br) {
//拿到错误,不会挡住请求
List<ObjectError> allErrors = br.getAllErrors();
for (ObjectError allError : allErrors) {
System.out.println(allError.getCode()+"---"+allError.getDefaultMessage());
}
System.out.println(user.getId());
return user;
}
注意点:
在需要校验的对象前加 @Validated注解。
在该对象后加一个参数:BindingResut 来接收校验信息。
调用 BindingResult 对象的 hasErrors 方法判断前台传过来的参数是否符合校验规则,有一个不符合规则,hasErrors 方法就会返回 true。
然后调用 getAllErrors() 方法获取 ObjectError 的 list 列表。
遍历集合,调用每个对象的 getDefaultMessage() 方法,获取相应的错误提示信息(在实体类上配置的)
获取到校验信息后再返回给前台或做一些其他的处理即可。
请求转发:
@RequestMapping("/annotation")
public String testAnnotation(Model model) {
model.addAttribute("annotation", "hello Springmvc");
return "annotation";
}
重定向:(只需要在return 语句中加入 redirect:+ 地址 即可访问)
@RequestMapping(value = "/jump")
public String jumpUser(HttpServletRequest request,HttpServletResponse response){
//return "redirect:https://www.baidu.com/";
return "redirect:add";
}
请求url | 请求方式 | 操作 |
---|---|---|
/admin/get/1 | get | 根据id查询用户 |
/admin/add | Post | 添加一个用户 |
/admin/update/1 | Put | 根据id修改用户 |
/admin/delete/1 | Delete | 删除一个用户 |
Restful web service是一种常见的rest的应用,是遵守了rest风格的web服务;rest式的web服务是一种ROA(The Resource-Oriented Architecture)(面向资源的架构)
常用状态码 工具类
/**
* @author 空巷
* @Date 2020/6/4
*/
@AllArgsConstructor
@Data
@NoArgsConstructor
public class R implements Serializable {
private int code;
private String msg;
private Map<String,String> data;
//返回成功后的信息
public static R success(){
return new R(200,"成功",null);
}
//返回失败后的信息
public static R fail(){
return new R(500,"fail",null);
}
//其他类型的返回
public static R build(int code,String msg){
return new R(500,msg,null);
}
public R put(String key,String msg){
if (msg == null){
this.getData().put(key,msg);
}
return this;
}
}
controller类
/**
* @author 空巷
* @Date 2020/6/4
*/
@Controller
@RequestMapping("/admin")
public class RestfulController {
@GetMapping("/get/{id}")
@ResponseBody
public User getUser(@PathVariable int id){
System.out.println(id);
return new User(13,"123","123456",new Date(),12123.12);
}
@PostMapping("/add")
@ResponseBody
public R addUser(User user){
System.out.println(user);
if (user == null){
return R.fail();
}else{
return R.success();
}
}
@PutMapping("/update/{id}")
@ResponseBody
public R updateUser(@PathVariable int id){
System.out.println(id);
return R.success();
}
@DeleteMapping("/delete/{id}")
@ResponseBody
public R deleteUser(@PathVariable int id){
System.out.println(id);
return R.success();
}
}
建立一个http文件或者在postman测试
GET http://localhost:8080/admin/get/1
Accept: application/json
###
POST http://localhost:8080/admin/add
Content-Type: text/html
###
PUT http://localhost:8080/admin/update/2
Content-Type: application/json
{
"id":2,
"username":"123",
"password":2,
"birthday":"2000-5-25",
"salary":"1,111.14"
}
###
DELETE http://localhost:8080/admin/delete/1
Content-Type: text/html
update 测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-81uCSZvO-1591533532699)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200604172838216.png)]
delete 测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9WFpgcgf-1591533532700)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200604173022938.png)]
get 测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HctHedNB-1591533532701)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200604173108784.png)]
add 测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ovlp1zQ5-1591533532702)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200604173200239.png)]
自定义的拦截器需要实现 Spring 的 HandlerInterceptor 接口,其中有三个方法。
/**
* @author 空巷
* @Date 2020/6/4
*/
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
if (user == null){
response.sendRedirect("/admin/toLogin");
}else {
return true;
}
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 {
}
}
还需要在 SpringMVC.xml 配置文件名中,配置编写的拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/toLogin"/>
<mvc:exclude-mapping path="/admin/login"/>
<bean id="loginInterceptor" class="com.xinzhi.interceptor.LoginInterceptor"/>
mvc:interceptor>
mvc:interceptors>
controller
@GetMapping("/toLogin")
public String toLogin(User user){
return "login";
}
@PostMapping("/login")
@ResponseBody
public R login(User user, HttpServletRequest request){
request.getSession().setAttribute("user",user);
return R.success();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n6xjbSrg-1591533532703)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200604184134261.png)]
Spring MVC 框架的文件上传是基于 commons-fileupload 组件的文件上传,只不过 Spring MVC 框架在原有文件上传组件上做了进一步封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。
commons-fileupload组件
由于 Spring MVC 框架的文件上传是基于 commons-fileupload 组件的文件上传,因此需要将 commons-fileupload 组件相关的 JAR(commons-fileupload-1.3.1.jar 和 commons-io-2.4.jar)复制到 Spring MVC 应用的 WEB-INF/lib 目录下。下面讲解如何下载相关 JAR 包。
Commons 是 Apache 开放源代码组织中的一个 Java 子项目,该项目包括文件上传、命令行处理、数据库连接池、XML 配置文件处理等模块。fileupload 就是其中用来处理基于表单的文件上传的子项目,commons-fileupload 组件性能优良,并支持任意大小文件的上传。文件上传
multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的CommonsFileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。
首先需要导入文件上传的 jar 包
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.3version>
dependency>
在 SpringMVC 中配置bean
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
bean>
CommonsMultipartFile 的 常用方法:
controller
@PostMapping("/upload")
@ResponseBody
public R upload(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request){
//getOriginalFilename 可以获得文件的名字
String filename = file.getOriginalFilename();
//文件路径
String path = "E:\\upload";
File relPath = new File(path);
//判断路径是否存在,不存在则创建一个
if (!relPath.exists()){
relPath.mkdir();
}
try {
file.transferTo(new File(path +"\\"+ filename));
} catch (IOException e) {
e.printStackTrace();
}
return R.success();
}
实现文件下载有以下两种方法:
使用 ResponseEntity
@GetMapping("/download")
public ResponseEntity<byte[]> download() {
String fileName = "6.png";
try {
//FileUtils 中有个方法 readFileToByteArray 可以读取文件
byte[] bytes = FileUtils.readFileToByteArray(new File("E:\\upload" + "\\" + fileName));
HttpHeaders handler = new HttpHeaders();
//下载文件时需要设置响应头
handler.set("Content-Disposition", "attachment;filename=" +
URLEncoder.encode(fileName, "UTF-8"));
handler.set("charsetEncoding", "utf-8");
handler.set("content-type", "multipart/form-data");
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(bytes, handler, HttpStatus.OK);
return responseEntity;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gsYxOaI3-1591533532704)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200604194010851.png)]
当页面出现异常时,不能显示在页面,之前是通过在web.xml配置错误页面,但往往这种处理办法是不好的。因为不知道他出现了什么错误。因此,Spring MVC提供了一个HandlerExceptionResolver接口,可用于统一异常处理。
/**
* @author 空巷
* @Date 2020/6/4
*/
@Component
public class MyException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
//打印错误到控制台
e.printStackTrace();
ModelAndView mv = new ModelAndView();
mv.setViewName("error");
return mv;
}
}
国际化是设计软件应用的过程中应用被使用与不同语言和地区
spring-mvc.xml配置文件
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
bean>
mvc:interceptor>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="zh_CN" />
bean>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="defaultEncoding" value="UTF-8" />
<property name="useCodeAsDefaultMessage" value="true" />
<property name="basenames">
<list>
<value>classpath:messagevalue>
list>
property>
bean>
国际化语言属性文件:message_zh_CN.properties
TITLE = 开始冒险之旅
USERNAME = 账号:
PASSWORD = 密码:
LOGIN = 登录
message_en_US.properties
TITLE = BEGIN TO START
USERNAME = UserName
PASSWORD = PassWord
LOGIN = Login
chinese.jsp
<%--
Created by IntelliJ IDEA.
User: 空巷
Date: 2020/6/4
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
中文
英文
controller
@GetMapping("/getLogin")
public String getLogin(){
return "result";
}
result.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%--
Created by IntelliJ IDEA.
User: 空巷
Date: 2020/6/4
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
pom依赖:
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.10.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.2.6.RELEASEversion>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.16.18version>
dependency>
dependencies>
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
mybatis-config.xml
一班用来开启驼峰式,别名等等
<configuration>
<typeAliases>
<package name="com.xinzhi.entity"/>
typeAliases>
configuration>
springmvc-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:default-servlet-handler />
<mvc:annotation-driven >
<mvc:message-converters>
<bean id="fastjson" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8value>
<value>application/json;charset=UTF-8value>
list>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
application.xml (配置数据源)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:property-placeholder location="classpath:db.properties"/>
<import resource="classpath:springmvc-servlet.xml"/>
<context:component-scan base-package="com.xinzhi"/>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xinzhi.dao"/>
bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mappers/*.xml"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
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="add*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="search*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.xinzhi.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
aop:config>
beans>
logback.xml(日志配置文件)
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="log.level" value="debug" />
<property name="log.maxHistory" value="0.5" />
<property name="log.filePath" value="D:/log" />
<property name="log.pattern"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" />
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}pattern>
encoder>
appender>
<appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.filePath}/debug.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.filePath}/debug/debug.%d{yyyy-MM-dd}.log.gz
fileNamePattern>
<maxHistory>${log.maxHistory}maxHistory>
rollingPolicy>
<encoder>
<pattern>${log.pattern}pattern>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUGlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.filePath}/info.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.filePath}/info/info.%d{yyyy-MM-dd}.log.gz
fileNamePattern>
<maxHistory>${log.maxHistory}maxHistory>
rollingPolicy>
<encoder>
<pattern>${log.pattern}pattern>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFOlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<logger name="com.xinzhi" level="${log.level}" additivity="true">
<appender-ref ref="debugAppender"/>
<appender-ref ref="infoAppender"/>
logger>
<root level="info">
<appender-ref ref="consoleAppender"/>
root>
<appender name="MyBatis" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.filePath}/sql_log/mybatis-sql.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.filePath}/sql_log/mybatis-sql.log.%d{yyyy-MM-dd}FileNamePattern>
<maxHistory>30maxHistory>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%thread|%d{yyyy-MM-dd HH:mm:ss.SSS}|%level|%logger{36}|%m%npattern>
encoder>
appender>
<logger name="sql" level="DEBUG">
<appender-ref ref="MyBatis"/>
logger>
configuration>
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/backlog?useSSL=false&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
filters=wall,stat
maxActive=20
initialSize=3
maxWait=5000
minIdle=3
maxIdle=15
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 'x'
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
maxOpenPreparedStatements=20
removeAbandoned=true
removeAbandonedTimeout=1800
logAbandoned=true
web.xml
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:application.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>DruidWebStatFilterfilter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilterfilter-class>
<init-param>
<param-name>exclusionsparam-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*param-value>
init-param>
filter>
<filter-mapping>
<filter-name>DruidWebStatFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet>
<servlet-name>DruidStatView servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServletservlet-class>
<init-param>
<param-name>loginUsernameparam-name>
<param-value>xinzhiparam-value>
init-param>
<init-param>
<param-name>loginPasswordparam-name>
<param-value>123param-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>DruidStatViewservlet-name>
<url-pattern>/druid/*url-pattern>
servlet-mapping>
web-app>
xxxMapper.xml
<mapper namespace="com.xinzhi.dao.UserMapper">
mapper>
静态资源的访问问题
访问 jsp 页面时 首先通过访问controller,通过请求转发到jsp页面 需要跳转首页时 建立一个indexConrtoller 使用GetMapping直接转发到首页
当一些页面的css,js等静态资源 放在WEB-INF 下,通过相对路径的方式是访问不到的
解决安案一:(不被保护的,外界可以查看)
将静态资源放入 webapp 下 通过 相对路径 或绝对路径的方式访问
解決方案二:(受保护的)
当把静态资源放入 WEB-INF 下的时候:
需要在spring-mvc配置文件中加入:
<mvc:resources mapping="/static/**" location="/WEB-INF/static/"/>
**eg: ** 当你使用了拦截器时,你会发现css等静态资源加不进来,打开 F12 进行调试,看到 css等静态资源并没有报红,你会发现,莫名其妙的重定向了。
解决方案一:(针对静态资源放入 webapp 下的处理办法)
在拦截器中加入
<mvc:exclude-mapping path="/**/*.css" />
<mvc:exclude-mapping path="/**/*.js" />
<mvc:exclude-mapping path="/**/*.jsp" />....
解决方案二:(针对静态资源存入WEB-INF 下)
在拦截器中加入
<mvc:exclude-mapping path="/static/**" />