发表于: 2019-11-21 22:43:27
2 1451
啥也不说就是干!!!
今天完成的事情:
1、SpringMVC 异常处理
SpringMVC 在处理请求过程中出现异常信息将会交给异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑
异常通常包含编译时异常和运行时异常
运行时异常,比如:空指针异常、数组越界异常
编译时异常,比如:数据库异常、文件读取异常、自定义异常。对于这样的异常必须使用try catch 代码块或 throws 关键字进行异常处理。
系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 SpringMVC 前端控制器交由异常处理器进行异常处理:
全局范围内只有一个异常处理器。
自定义异常类:为了区别不同的异常通常根据异常类型自定义异常类,这里我们创建一个自定义系统异常,如果 Controller、service、dao 抛出此类异常说明系统预期处理的异常信息。
public class CustomException extends Exception {
private String message;
public CustomException(String message) {
super(message);
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
自定义异常处理器 GlobalExceptionHandler
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler{
private static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public Result<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
logger.error("参数解析失败", e);
return Result.failed("could_not_read_json");
}
/**
* 405 - Method Not Allowed
*/
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Result<String> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
logger.error("不支持当前请求方法", e);
return Result.failed("request_method_not_supported");
}
/**
* 415 - Unsupported Media Type
*/
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public Result<String> handleHttpMediaTypeNotSupportedException(Exception e) {
logger.error("不支持当前媒体类型", e);
return Result.failed("content_type_not_supported");
}
/**
* 500 - Internal Server Error
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public Result<String> handleException(Exception e) {
if (e instanceof CustomException){
return Result.failed(e.getMessage());
}
logger.error("服务运行异常", e);
e.printStackTrace();
return Result.failed("server_error");
}
}
2、SpringMVC 参数校验
为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,同时也可以避免恶意请求,Spring的 javax.validation 注解式参数校验可以很好的帮助我们实现对参数的校验
1)什么是 javax.validation
JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面(面向注解编程的时代),就可以在需要校验的时候进行校验了
2)添加相关依赖:
3)常用注解说明:
验证注解 | 验证的数据类型 | 说明 |
@AssertFalse | boolean,Boolean | 验证注解的元素值false |
@AssertTrue | boolean,Boolean | 验证注解的元素值是true |
@NotNull | 任意类型 | 验证注解的元素值不是 null |
@Null | 任意类型 | 验证注解的元素值是 null |
@Min(value=值) | short,int,long,Number(数字类型) | 验证注解的元素值大于等于@Min指定的value值 |
@Max(value=值) | 和@Min要求一样 | 验证注解的元素值小于等于@Max指定的value值 |
@Past | 日期类型 | 验证注解的元素值(日期类型)比当前时间早 |
@Future | 与@Past要求一样 | 验证注解的元素值(日期类型)比当前时间晚 |
@NotBlank | CharSequence子类型 | 验证注解的元素值不为空(不为null、去除首位空格后长度为0) |
@Length(min=下限, max=上限) | CharSequence子类型 | 验证注解的元素值长度在min和max区间内 |
@NotEmpty | CharSequence子类型、Collection、Map、数组 | 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) |
@Email(regexp=正则表达式,flag=标志的模式) | CharSequence子类型(如String) | 验证注解的元素值是Email |
4)项目中的使用:
@Validated 声明要检查的参数(Controller 方法入参)
@RequestMapping(value = "/",method = RequestMethod.POST)
@ResponseBody
public Result<Integer> addStudentInfo(@Validated Student student){
int id = studentService.addStudent(student);
String msg = "";
if(id>0){
msg="插入成功";
}
else{
msg="插入失败";
}
return Result.success(id,msg);
}
对参数的字段进行注解标注:
@Data
public class Student {
private int id;
@NotBlank(message = "用户名不能为空")
private String name;
@NotBlank(message = "学号不能为空")
private String onlineNum;
@NotBlank(message = "修真类型不能为空")private String jnshuType;
}
在全局异常处理中添加校验异常
MethodArgumentNotValidException 是绑定参数校验的异常,需要在SpringMVC 中处理,还需要对 ConstraintViolationException 异常进行处理
@ExceptionHandler(value = {BindException.class, MethodArgumentNotValidException.class})
public Result<String> validationExceptionHandler(Exception exception) {
BindingResult bindResult = null;
if (exception instanceof BindException) {
bindResult = ((BindException) exception).getBindingResult();
} else if (exception instanceof MethodArgumentNotValidException) {
bindResult = ((MethodArgumentNotValidException) exception).getBindingResult();
}
String msg;
if (bindResult != null && bindResult.hasErrors()) {
msg = bindResult.getAllErrors().get(0).getDefaultMessage();
if (msg.contains("NumberFormatException")) {
msg = "参数类型错误!";
}
}else {
msg = "系统繁忙,请稍后重试...";
}
return Result.failed(-1, msg);
}
可以看到如果用户名传空值的话,请求如下:
3、前端页面之增删改查
查询学生信息列表(分页)
StudentController 查询学生信息方法:
@RequestMapping(value = "/",method = RequestMethod.GET)
public String getStudentList(Model model, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize){
PageInfo<Student> pageInfo = studentService.getStudentList(pageNum,pageSize);
model.addAttribute("pageInfo",pageInfo);
return "student_list";
}
学生信息列表页面 student_list.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>monkey1024</title>
<link href="${pageContext.request.contextPath}/static/bootstrap-3.3.7-dist/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="container theme-showcase" role="main">
<div class="page-header">
<a id="add" type="button" class="btn btn-sm btn-success" href="${pageContext.request.contextPath}/jsp/student_add.jsp">添加</a>
</div>
<div class="row">
<div class="">
<table class="table table-striped">
<thead>
<tr>
<th>编号</th>
<th>姓名</th>
<th>QQ</th>
<th>修真类型</th>
<th>毕业学校</th>
<th>学号</th>
<th>辅导师兄</th>
<th>口号</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<c:forEach items="${pageInfo.list}" var="stu">
<tr>
<td>${stu.id}</td>
<td>${stu.name}</td>
<td>${stu.qq}</td>
<td>${stu.jnshuType}</td>
<td>${stu.school}</td>
<td>${stu.onlineNum}</td>
<td>${stu.counsellor}</td>
<td>${stu.slogan}</td>
<td>
<a type="button" class="btn btn-sm btn-warning" href="${pageContext.request.contextPath}/jsp/student_update.jsp?id=${stu.id}&slogan=${stu.slogan}">修改</a>
<form action="${pageContext.request.contextPath}/student/${stu.id}" method="post" >
<input name="_method" type="hidden" value="DELETE">
<input type="submit" class="btn btn-sm btn-info" value="删除">
</form>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="900px">
<tr>
<td class="td2">
<span>第${pageInfo.pageNum}/ ${pageInfo.pages}页</span>
<span>总记录数:${pageInfo.total} 每页显示:${pageInfo.pageSize}</span>
<span>
<c:if test="${pageInfo.pageNum != 5}">
<a href="${pageContext.request.contextPath }/student/">[首页]</a>
<a href="${pageContext.request.contextPath }/student/?pageNum=${pageInfo.pageNum-1}">[上一页]</a>
</c:if>
<c:if test="${pageInfo.pageNum != pageInfo.total}">
<a href="${pageContext.request.contextPath }/student/?pageNum=${pageInfo.pageNum+1}">[下一页]</a>
<a href="${pageContext.request.contextPath }/student/?pageNum=${pageInfo.total}">[尾页]</a>
</c:if>
</span>
</td>
</tr>
</table>
</div>
</div>
</div>
<script src="${pageContext.request.contextPath}/static/jquery-3.3.1.min.js"></script>
<script src="${pageContext.request.contextPath}/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
</body>
</html>
浏览器发送请求:http://localhost:8080/JnshuTask2/student/,看到页面效果如下:
添加学生信息
StudentController 新增学生信息方法:
@RequestMapping(value = "/",method = RequestMethod.POST)
public String addStudentInfo(@Validated Student student){
int id = studentService.addStudent(student);
return "redirect:/student/";
}
新增学生信息页面 student_add.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>monkey1024</title>
<link href="${pageContext.request.contextPath}/static/bootstrap-3.3.7-dist/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="page-header"></div>
<div class="container">
<form action="${pageContext.request.contextPath}/student/" method="post" style="max-width: 330px;padding: 15px;margin: 0 auto;">
<div class="form-group">
<label for="name">姓名:</label>
<input type="text" class="form-control" id="name" name="name">
</div>
<div class="form-group">
<label for="qq">qq:</label>
<input type="text" class="form-control" id="qq" name="qq">
</div>
<div class="form-group">
<label for="school">毕业学校:</label>
<input type="text" class="form-control" id="school" name="school">
</div>
<div class="form-group">
<label for="jnshuType">修真类型:</label>
<input type="text" class="form-control" id="jnshuType" name="jnshuType">
</div>
<div class="form-group">
<label for="onlineNum">学号:</label>
<input type="text" class="form-control" id="onlineNum" name="onlineNum">
</div>
<div class="form-group">
<label for="counsellor">辅导师兄:</label>
<input type="text" class="form-control" id="counsellor" name="counsellor">
</div>
<div class="form-group">
<label for="slogan">口号:</label>
<input type="text" class="form-control" id="slogan" name="slogan">
</div>
<input type="submit" value="提交">
</form>
</div>
<script src="${pageContext.request.contextPath}/static/jquery-3.3.1.min.js"></script>
<script src="${pageContext.request.contextPath}/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
</body>
</html>
修改学生信息
StudentController 修改学生信息方法:
@RequestMapping(value = "/{id}",method = RequestMethod.PUT)
public String updateSlogan(@PathVariable Integer id,String slogan){
int row = studentService.updateSloganById(id,slogan);
return "redirect:/student/";
}
修改学生信息页面 student_update.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false"%>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>monkey1024</title>
<link href="${pageContext.request.contextPath}/static/bootstrap-3.3.7-dist/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="page-header"></div>
<div class="container">
<form action="${pageContext.request.contextPath}/student/${param.id}" method="post" style="max-width: 330px;padding: 15px;margin: 0 auto;">
<input name="id" type="hidden" value="${param.id}">
<input name="_method" type="hidden" value="PUT">
<div class="form-group">
<label for="slogan">口号:</label>
<input type="text" class="form-control" id="slogan" name="slogan" value="${param.slogan}">
</div>
<input type="submit" value="修改">
</form>
</div>
<script src="${pageContext.request.contextPath}/static/jquery-3.3.1.min.js"></script>
<script src="${pageContext.request.contextPath}/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
</body>
</html>
修改成功,重定向到 student_list.jsp
删除学生信息
StudentController 删除学生信息方法:
@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
public String deleteStudentInfo(@PathVariable Integer id){
int row = studentService.deleteStudentById(id);
return "redirect:/student/";
}
删除成功重定向至 student_list.jsp
由于 form 表单不支持 PUT DELETE 方法的提交,
所以需要在 web.xml 配置文件中配置相关的过滤器,使得 POST 请求 可以转化为 PUT DELETE 请求
<!--配置 HiddenHttpMethodFilter: 把 POST 请求转为 DELETE、PUT 请求 -->
<filter>
<filter-name>HttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
并且 <input> 标签还需要设置 _method hidden 域
明天计划的事情:
1、项目部署至 远程服务器(tomcat)
2、学习配置 Nginx
遇到的问题:
无
收获:
SpringMVC 参数校验及全局异常处理
评论