forked from itwanger/toBeBetterJavaer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidator.html
More file actions
198 lines (184 loc) · 71.8 KB
/
validator.html
File metadata and controls
198 lines (184 loc) · 71.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="generator" content="VuePress 2.0.0-beta.46" />
<meta name="theme" content="VuePress Theme Hope" />
<meta property="og:url" content="https://tobebetterjavaer.com/springboot/validator.html"><meta property="og:site_name" content="Java 程序员进阶之路"><meta property="og:title" content="SpringBoot中处理校验逻辑的两种方式:Hibernate Validator+全局异常处理"><meta property="og:type" content="article"><meta property="og:updated_time" content="2022-06-14T06:46:15.000Z"><meta property="og:locale" content="zh-CN"><meta property="article:tag" content="Spring Boot"><meta property="article:modified_time" content="2022-06-14T06:46:15.000Z"><script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?5230ac143650bf5eb3c14f3fb9b1d3ec";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script><link rel="stylesheet" href="//at.alicdn.com/t/font_3180624_7cy10l7jqqh.css"><link rel="icon" href="/favicon.ico"><link rel="icon" href="/assets/icon/chrome-mask-512.png" type="image/png" sizes="512x512"><link rel="icon" href="/assets/icon/chrome-mask-192.png" type="image/png" sizes="192x192"><link rel="icon" href="/assets/icon/chrome-512.png" type="image/png" sizes="512x512"><link rel="icon" href="/assets/icon/chrome-192.png" type="image/png" sizes="192x192"><link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials"><meta name="theme-color" content="#46bd87"><link rel="apple-touch-icon" href="/assets/icon/apple-icon-152.png"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="msapplication-TileImage" content="/assets/icon/ms-icon-144.png"><meta name="msapplication-TileColor" content="#ffffff"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"><title>SpringBoot中处理校验逻辑的两种方式:Hibernate Validator+全局异常处理 | Java 程序员进阶之路</title><meta name="description" content="一份通俗易懂、风趣幽默的Java学习指南,内容涵盖Java基础、Java并发编程、Java虚拟机、Java企业级开发、Java面试等核心知识点。学Java,就认准Java程序员进阶之路">
<style>
:root {
--bg-color: #fff;
}
html[data-theme="dark"] {
--bg-color: #1d2025;
}
html,
body {
background-color: var(--bg-color);
}
</style>
<script>
const userMode = localStorage.getItem("vuepress-theme-hope-scheme");
const systemDarkMode =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
if (userMode === "dark" || (userMode !== "light" && systemDarkMode)) {
document.querySelector("html").setAttribute("data-theme", "dark");
}
</script>
<link rel="stylesheet" href="/assets/style.c081fa20.css">
<link rel="modulepreload" href="/assets/app.41bad062.js"><link rel="modulepreload" href="/assets/validator.html.59f1216c.js"><link rel="modulepreload" href="/assets/plugin-vue_export-helper.21dcd24c.js"><link rel="modulepreload" href="/assets/validator.html.cceaae3a.js">
</head>
<body>
<div id="app"><!--[--><!--[--><!--[--><span tabindex="-1"></span><a href="#main-content" class="skip-link sr-only">Skip to content</a><!--]--><div class="theme-container has-toc"><!--[--><!--[--><header class="navbar"><div class="navbar-left"><button class="toggle-sidebar-button" title="Toggle Sidebar"><span class="icon"></span></button><!----><a href="/" class="brand"><img class="logo" src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/logo-02.png" alt="Java 程序员进阶之路"><!----><span class="site-name hide-in-pad">Java 程序员进阶之路</span></a><!----></div><div class="navbar-center"><!----><nav class="nav-links"><div class="nav-item hide-in-mobile"><a href="/blog.html" class="nav-link" aria-label="博客"><span class="icon iconfont icon-gaishu" style=""></span>博客<!----></a></div><div class="nav-item hide-in-mobile"><a href="/home.html" class="nav-link" aria-label="进阶之路"><span class="icon iconfont icon-lujing" style=""></span>进阶之路<!----></a></div><div class="nav-item hide-in-mobile"><a href="/zhishixingqiu/" class="nav-link" aria-label="知识星球"><span class="icon iconfont icon-Artboard" style=""></span>知识星球<!----></a></div><div class="nav-item hide-in-mobile"><a href="/xuexiluxian/" class="nav-link" aria-label="学习路线"><span class="icon iconfont icon-luxian" style=""></span>学习路线<!----></a></div><div class="nav-item hide-in-mobile"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="珍藏资源"><span class="title"><span class="icon iconfont icon-youzhi" style=""></span>珍藏资源</span><span class="arrow"></span><ul class="nav-dropdown"><li class="dropdown-item"><a href="/download/java.html" class="nav-link" aria-label="电子书下载"><span class="icon iconfont icon-java" style=""></span>电子书下载<!----></a></li><li class="dropdown-item"><a href="/sidebar/sanfene/nixi.html" class="nav-link" aria-label="面渣逆袭"><span class="icon iconfont icon-zhunbei" style=""></span>面渣逆袭<!----></a></li><li class="dropdown-item"><a href="/download/nicearticle.html" class="nav-link" aria-label="优质文章"><span class="icon iconfont icon-youzhi" style=""></span>优质文章<!----></a></li><li class="dropdown-item"><a href="/download/history.html" class="nav-link" aria-label="网络日志"><span class="icon iconfont icon-rizhi" style=""></span>网络日志<!----></a></li><li class="dropdown-item"><a href="/nice-article/itmind/" class="nav-link" aria-label="破解合集"><span class="icon iconfont icon-zhongyaotishi" style=""></span>破解合集<!----></a></li></ul></button></div></div><div class="nav-item hide-in-mobile"><a href="https://space.bilibili.com/513340480" rel="noopener noreferrer" target="_blank" aria-label="B站视频" class="nav-link"><span class="icon iconfont icon-bzhan" style=""></span>B站视频<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div></nav><!----></div><div class="navbar-right"><!----><div class="nav-item"><!----></div><div class="nav-item"><a class="repo-link" href="https://github.com/itwanger/toBeBetterJavaer" target="_blank" rel="noopener noreferrer"><svg xmlns="http://www.w3.org/2000/svg" class="icon github-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="github icon" style="width:1.25rem;height:1.25rem;vertical-align:middle;"><path d="M511.957 21.333C241.024 21.333 21.333 240.981 21.333 512c0 216.832 140.544 400.725 335.574 465.664 24.49 4.395 32.256-10.07 32.256-23.083 0-11.69.256-44.245 0-85.205-136.448 29.61-164.736-64.64-164.736-64.64-22.315-56.704-54.4-71.765-54.4-71.765-44.587-30.464 3.285-29.824 3.285-29.824 49.195 3.413 75.179 50.517 75.179 50.517 43.776 75.008 114.816 53.333 142.762 40.79 4.523-31.66 17.152-53.377 31.19-65.537-108.971-12.458-223.488-54.485-223.488-242.602 0-53.547 19.114-97.323 50.517-131.67-5.035-12.33-21.93-62.293 4.779-129.834 0 0 41.258-13.184 134.912 50.346a469.803 469.803 0 0 1 122.88-16.554c41.642.213 83.626 5.632 122.88 16.554 93.653-63.488 134.784-50.346 134.784-50.346 26.752 67.541 9.898 117.504 4.864 129.834 31.402 34.347 50.474 78.123 50.474 131.67 0 188.586-114.73 230.016-224.042 242.09 17.578 15.232 33.578 44.672 33.578 90.454v135.85c0 13.142 7.936 27.606 32.854 22.87C862.25 912.597 1002.667 728.747 1002.667 512c0-271.019-219.648-490.667-490.71-490.667z"></path></svg></a></div><div class="nav-item hide-in-mobile"><button id="appearance-switch"><svg xmlns="http://www.w3.org/2000/svg" class="icon auto-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="auto icon" style="display:block;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="dark icon" style="display:none;"><path d="M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="light icon" style="display:none;"><path d="M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"></path></svg></button></div><div id="docsearch-container"></div><!----><button class="toggle-navbar-button" aria-label="Toggle Navbar" aria-expanded="false" aria-controls="nav-screen"><span class="button-container"><span class="button-top"></span><span class="button-middle"></span><span class="button-bottom"></span></span></button></div></header><!----><!--]--><!----><div class="toggle-sidebar-wrapper"><span class="arrow left"></span></div><aside class="sidebar"><!--[--><!----><!--]--><ul class="sidebar-links"><li><!--[--><a href="/home.html" class="nav-link sidebar-link sidebar-page" aria-label="一、前言"><!---->一、前言<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">二、Java核心</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable active"><!----><span class="title">三、Java企业级开发</span><span class="arrow down"></span></button><ul class="sidebar-links"><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">3.1 开发工具</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">3.2 IDE/编辑器</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">3.3 Spring</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable active"><!----><span class="title">3.4 SpringBoot</span><span class="arrow down"></span></button><ul class="sidebar-links"><li><!--[--><a href="/springboot/initializr.html" class="nav-link sidebar-link sidebar-page" aria-label="搭建第一个Spring Boot项目"><!---->搭建第一个Spring Boot项目<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/mysql-druid.html" class="nav-link sidebar-link sidebar-page" aria-label="整合MySQL和Druid"><!---->整合MySQL和Druid<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/jpa.html" class="nav-link sidebar-link sidebar-page" aria-label="整合JPA"><!---->整合JPA<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/thymeleaf.html" class="nav-link sidebar-link sidebar-page" aria-label="整合Thymeleaf"><!---->整合Thymeleaf<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/transaction.html" class="nav-link sidebar-link sidebar-page" aria-label="开启事务支持"><!---->开启事务支持<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/Filter-Interceptor-Listener.html" class="nav-link sidebar-link sidebar-page" aria-label="过滤器、拦截器、监听器"><!---->过滤器、拦截器、监听器<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/redis/redis-springboot.html" class="nav-link sidebar-link sidebar-page" aria-label="整合Redis实现缓存"><!---->整合Redis实现缓存<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/logback.html" class="nav-link sidebar-link sidebar-page" aria-label="整合Logback"><!---->整合Logback<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/swagger.html" class="nav-link sidebar-link sidebar-page" aria-label="整合Swagger-UI"><!---->整合Swagger-UI<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/gongju/knife4j.html" class="nav-link sidebar-link sidebar-page" aria-label="整合Knife4j"><!---->整合Knife4j<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/springtask.html" class="nav-link sidebar-link sidebar-page" aria-label="整合SpringTask"><!---->整合SpringTask<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/kaiyuan/auto-generator.html" class="nav-link sidebar-link sidebar-page" aria-label="整合MyBatis-Plus AutoGenerator"><!---->整合MyBatis-Plus AutoGenerator<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/quartz.html" class="nav-link sidebar-link sidebar-page" aria-label="整合Quartz"><!---->整合Quartz<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/mybatis.html" class="nav-link sidebar-link sidebar-page" aria-label="整合MyBatis"><!---->整合MyBatis<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/docker.html" class="nav-link sidebar-link sidebar-page" aria-label="部署SpringBoot到Docker"><!---->部署SpringBoot到Docker<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/macos-codingmore-run.html" class="nav-link sidebar-link sidebar-page" aria-label="macOS下如何运行编程喵源码"><!---->macOS下如何运行编程喵源码<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/windows-codingmore-run.html" class="nav-link sidebar-link sidebar-page" aria-label="Windows下如何运行编程喵源码"><!---->Windows下如何运行编程喵源码<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/springboot/linux-codingmore-run.html" class="nav-link sidebar-link sidebar-page" aria-label="一键部署编程喵到生产环境"><!---->一键部署编程喵到生产环境<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a aria-current="page" href="/springboot/validator.html" class="router-link-active router-link-exact-active nav-link active sidebar-link sidebar-page active" aria-label="SpringBoot中如何处理校验逻辑"><!---->SpringBoot中如何处理校验逻辑<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/springboot/validator.html#一、hibernate-validator" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="一、Hibernate Validator"><!---->一、Hibernate Validator<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/springboot/validator.html#二、全局异常处理" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="二、全局异常处理"><!---->二、全局异常处理<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/springboot/validator.html#三、总结" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="三、总结"><!---->三、总结<!----></a><ul class="sidebar-sub-headers"></ul></li></ul><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">3.5 辅助工具</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">3.6 开源轮子</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">3.7 分布式</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">3.8 消息队列</span><span class="arrow right"></span></button><!----></section><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">四、数据库</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">五、计算机基础</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">六、求职面试</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">七、学习资源</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">八、学习建议</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">九、知识库搭建</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">十、联系作者</span><span class="arrow right"></span></button><!----></section><!--]--></li></ul><!--[--><!----><!--]--></aside><!--[--><main class="page" id="main-content"><!--[--><!----><nav class="breadcrumb disable"></nav><div class="page-title"><h1><!---->SpringBoot中处理校验逻辑的两种方式:Hibernate Validator+全局异常处理</h1><div class="page-info"><span class="author-info" aria-label="作者🖊" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon author-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="author icon"><path d="M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z"></path></svg><span><a class="author-item" href="/about-the-author/" target="_blank" rel="noopener noreferrer">沉默王二</a></span><span property="author" content="沉默王二"></span></span><!----><span class="date-info" aria-label="写作日期📅" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon calendar-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="calendar icon"><path d="M716.4 110.137c0-18.753-14.72-33.473-33.472-33.473-18.753 0-33.473 14.72-33.473 33.473v33.473h66.993v-33.473zm-334.87 0c0-18.753-14.72-33.473-33.473-33.473s-33.52 14.72-33.52 33.473v33.473h66.993v-33.473zm468.81 33.52H716.4v100.465c0 18.753-14.72 33.473-33.472 33.473a33.145 33.145 0 01-33.473-33.473V143.657H381.53v100.465c0 18.753-14.72 33.473-33.473 33.473a33.145 33.145 0 01-33.473-33.473V143.657H180.6A134.314 134.314 0 0046.66 277.595v535.756A134.314 134.314 0 00180.6 947.289h669.74a134.36 134.36 0 00133.94-133.938V277.595a134.314 134.314 0 00-133.94-133.938zm33.473 267.877H147.126a33.145 33.145 0 01-33.473-33.473c0-18.752 14.72-33.473 33.473-33.473h736.687c18.752 0 33.472 14.72 33.472 33.473a33.145 33.145 0 01-33.472 33.473z"></path></svg><span>2022年6月14日</span><meta property="datePublished" content="2022-06-14T06:46:15.000Z"></span><span class="category-info" aria-label="分类🌈" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon category-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="category icon"><path d="M148.41 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H148.41c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.311-40.31zM147.556 553.478H429.73c22.263 0 40.311 18.048 40.311 40.31v282.176c0 22.263-18.048 40.312-40.31 40.312H147.555c-22.263 0-40.311-18.049-40.311-40.312V593.79c0-22.263 18.048-40.311 40.31-40.311zM593.927 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H593.927c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.31-40.31zM730.22 920.502H623.926c-40.925 0-74.22-33.388-74.22-74.425V623.992c0-41.038 33.387-74.424 74.425-74.424h222.085c41.038 0 74.424 33.226 74.424 74.067v114.233c0 10.244-8.304 18.548-18.547 18.548s-18.548-8.304-18.548-18.548V623.635c0-20.388-16.746-36.974-37.33-36.974H624.13c-20.585 0-37.331 16.747-37.331 37.33v222.086c0 20.585 16.654 37.331 37.126 37.331H730.22c10.243 0 18.547 8.304 18.547 18.547 0 10.244-8.304 18.547-18.547 18.547z"></path></svg><ul class="categories-wrapper"><li class="category category5 clickable" role="navigation">Java企业级开发</li><meta property="articleSection" content="Java企业级开发"></ul></span><span aria-label="标签🏷" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon tag-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="tag icon"><path d="M939.902 458.563L910.17 144.567c-1.507-16.272-14.465-29.13-30.737-30.737L565.438 84.098h-.402c-3.215 0-5.726 1.005-7.634 2.913l-470.39 470.39a10.004 10.004 0 000 14.164l365.423 365.424c1.909 1.908 4.42 2.913 7.132 2.913s5.223-1.005 7.132-2.913l470.39-470.39c2.01-2.11 3.014-5.023 2.813-8.036zm-240.067-72.121c-35.458 0-64.286-28.828-64.286-64.286s28.828-64.285 64.286-64.285 64.286 28.828 64.286 64.285-28.829 64.286-64.286 64.286z"></path></svg><ul class="tags-wrapper"><li class="tag tag1 clickable" role="navigation">Spring Boot</li></ul><meta property="keywords" content="Spring Boot"></span><span class="reading-time-info" aria-label="阅读时间⌛" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon timer-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="timer icon"><path d="M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z"></path></svg><span>大约 6 分钟</span><meta property="timeRequired" content="PT6M"></span></div><hr></div><div class="toc-place-holder"><aside id="toc"><div class="toc-header">此页内容</div><div class="toc-wrapper"><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/springboot/validator.html#一、hibernate-validator" class="router-link-active router-link-exact-active toc-link level3">一、Hibernate Validator</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/springboot/validator.html#二、全局异常处理" class="router-link-active router-link-exact-active toc-link level3">二、全局异常处理</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/springboot/validator.html#三、总结" class="router-link-active router-link-exact-active toc-link level3">三、总结</a></li><!----><!--]--></ul></div></aside></div><!----><div class="theme-hope-content"><p>最近正在开发一个知识库学习网站编程喵🐱,需要对请求参数进行校验,比如说非空啊、长度限制啊等等,可选的解决方案有两种:</p><ul><li>一种是用 Hibernate Validator 来处理</li><li>一种是用全局异常来处理</li></ul><p>两种方式,我们一一来实践体验一下。</p><h3 id="一、hibernate-validator" tabindex="-1"><a class="header-anchor" href="#一、hibernate-validator" aria-hidden="true">#</a> 一、Hibernate Validator</h3><p>Spring Boot 已经内置了 Hibernate Validator 校验框架,这个可以通过 Spring Boot 官网查看和确认。</p><p>第一步,进入 Spring Boot 官网,点击 learn 这个面板,点击参考文档。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/springboot/validator-9585b744-a942-425f-b78b-f92f22909c6c.png" alt=""></p><p>第二步,在参考文档页点击「依赖的版本」。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/springboot/validator-5b9e4758-27ff-4773-a4b3-809b8dd6546c.png" alt=""></p><p>第三步,在依赖版本页就可以查看到所有的依赖了,包括版本号。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/springboot/validator-2b0b00c2-fc10-40dc-bfc7-c615bd87f9c9.png" alt=""></p><p>PS:如果发现没有起效,可能是依赖版本冲突了,手动把 Hibernate Validator 依赖添加到 pom.xml 文件就可以了。</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code><dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 Hibernate Validator 校验框架,我们可以直接在请求参数的字段上加入注解来完成校验。</p><p><strong>具体该怎么做呢</strong>?</p><p>第一步,在需要验证的字段上加上 Hibernate Validator 提供的校验注解。</p><p>比如说我现在有一个用户名和密码登录的请求参数 UsersLoginParam 类:</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Data</span>
<span class="token annotation punctuation">@ApiModel</span><span class="token punctuation">(</span>value<span class="token operator">=</span><span class="token string">"用户登录"</span><span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">"用户表"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UsersLoginParam</span> <span class="token keyword">implements</span> <span class="token class-name">Serializable</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">long</span> serialVersionUID <span class="token operator">=</span> <span class="token number">1L</span><span class="token punctuation">;</span>
<span class="token annotation punctuation">@ApiModelProperty</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"登录名"</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@NotBlank</span><span class="token punctuation">(</span>message<span class="token operator">=</span><span class="token string">"登录名不能为空"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> userLogin<span class="token punctuation">;</span>
<span class="token annotation punctuation">@ApiModelProperty</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"密码"</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@NotBlank</span><span class="token punctuation">(</span>message<span class="token operator">=</span><span class="token string">"密码不能为空"</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> userPass<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>就可以通过 <code>@NotBlank</code> 注解来对用户名和密码进行判空校验。除了 <code>@NotBlank</code> 注解,Hibernate Validator 还提供了以下常用注解:</p><ul><li><code>@NotNull</code>:被注解的字段不能为 null;</li><li><code>@NotEmpty</code>:被注解的字段不能为空;</li><li><code>@Min</code>:被注解的字段必须大于等于其value值;</li><li><code>@Max</code>:被注解的字段必须小于等于其value值;</li><li><code>@Size</code>:被注解的字段必须在其min和max值之间;</li><li><code>@Pattern</code>:被注解的字段必须符合所定义的正则表达式;</li><li><code>@Email</code>:被注解的字段必须符合邮箱格式。</li></ul><p>第二步,在对应的请求接口(<code>UsersController.login()</code>)中添加 <code>@Validated</code> 注解,并注入一个 <code>BindingResult</code> 参数。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Controller</span>
<span class="token annotation punctuation">@Api</span><span class="token punctuation">(</span>tags<span class="token operator">=</span><span class="token string">"用户"</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/users"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UsersController</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">IUsersService</span> usersService<span class="token punctuation">;</span>
<span class="token annotation punctuation">@ApiOperation</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"登录以后返回token"</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"/login"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
<span class="token annotation punctuation">@ResponseBody</span>
<span class="token keyword">public</span> <span class="token class-name">ResultObject</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Validated</span> <span class="token class-name">UsersLoginParam</span> users<span class="token punctuation">,</span> <span class="token class-name">BindingResult</span> result<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> token <span class="token operator">=</span> usersService<span class="token punctuation">.</span><span class="token function">login</span><span class="token punctuation">(</span>users<span class="token punctuation">.</span><span class="token function">getUserLogin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> users<span class="token punctuation">.</span><span class="token function">getUserPass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token class-name">ResultObject</span><span class="token punctuation">.</span><span class="token function">validateFailed</span><span class="token punctuation">(</span><span class="token string">"用户名或密码错误"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">></span></span> tokenMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation"><</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
tokenMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"token"</span><span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">;</span>
tokenMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"tokenHead"</span><span class="token punctuation">,</span> tokenHead<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token class-name">ResultObject</span><span class="token punctuation">.</span><span class="token function">success</span><span class="token punctuation">(</span>tokenMap<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>第三步,为控制层(UsersController)创建一个切面,将通知注入到 BindingResult 对象中,然后再判断是否有校验错误,有错误的话返回校验提示信息,否则放行。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Aspect</span>
<span class="token annotation punctuation">@Component</span>
<span class="token annotation punctuation">@Order</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">BindingResultAspect</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Pointcut</span><span class="token punctuation">(</span><span class="token string">"execution(public * com.codingmore.controller.*.*(..))"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token class-name">BindingResult</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Around</span><span class="token punctuation">(</span><span class="token string">"BindingResult()"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">doAround</span><span class="token punctuation">(</span><span class="token class-name">ProceedingJoinPoint</span> joinPoint<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">{</span>
<span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args <span class="token operator">=</span> joinPoint<span class="token punctuation">.</span><span class="token function">getArgs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Object</span> arg <span class="token operator">:</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>arg <span class="token keyword">instanceof</span> <span class="token class-name">BindingResult</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">BindingResult</span> result <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">BindingResult</span><span class="token punctuation">)</span> arg<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token function">hasErrors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">FieldError</span> fieldError <span class="token operator">=</span> result<span class="token punctuation">.</span><span class="token function">getFieldError</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>fieldError<span class="token operator">!=</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token class-name">ResultObject</span><span class="token punctuation">.</span><span class="token function">validateFailed</span><span class="token punctuation">(</span>fieldError<span class="token punctuation">.</span><span class="token function">getDefaultMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token class-name">ResultObject</span><span class="token punctuation">.</span><span class="token function">validateFailed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> joinPoint<span class="token punctuation">.</span><span class="token function">proceed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这里涉及到了 Spring AOP 的知识,我在前面的文章里讲解过了,戳这个链接可以直达:<a href="https://tobebetterjavaer.com/springboot/aop-log.html" target="_blank" rel="noopener noreferrer">Spring AOP 扫盲<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p>第四步,访问登录接口,用户名和密码都不传入的情况下,就会返回“用户名不能为空”的提示信息。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/springboot/validator-eaf30b98-0a9a-403f-8f2b-a159edc492d6.png" alt=""></p><p>通过 debug 的形式,体验一下整个工作流程。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/springboot/validator-bc9d8ec7-bba6-4306-aaae-b6c66068366a.png" alt=""></p><p>可以看得出,Hibernate Validator 带来的优势有这些:</p><ul><li>验证逻辑与业务逻辑进行了分离,降低了程序耦合度;</li><li>统一且规范的验证方式,无需再次编写重复的验证代码。</li></ul><p>不过,也带来一些弊端,比如说:</p><ul><li>需要在请求接口的方法中注入 BindingResult 对象,而这个对应在方法体中并没有用到</li><li>只能校验一些非常简单的逻辑,涉及到数据查询就无能为力了。</li></ul><h3 id="二、全局异常处理" tabindex="-1"><a class="header-anchor" href="#二、全局异常处理" aria-hidden="true">#</a> 二、全局异常处理</h3><p>使用全局异常处理的优点就是比较灵活,可以处理比较复杂的逻辑校验,在校验失败的时候直接抛出异常,然后进行捕获处理就可以了。</p><p>第一步,新建一个自定义异常类 ApiException。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ApiException</span> <span class="token keyword">extends</span> <span class="token class-name">RuntimeException</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token class-name">IErrorCode</span> errorCode<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token class-name">ApiException</span><span class="token punctuation">(</span><span class="token class-name">IErrorCode</span> errorCode<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">super</span><span class="token punctuation">(</span>errorCode<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>errorCode <span class="token operator">=</span> errorCode<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">ApiException</span><span class="token punctuation">(</span><span class="token class-name">String</span> message<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">super</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">ApiException</span><span class="token punctuation">(</span><span class="token class-name">Throwable</span> cause<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">super</span><span class="token punctuation">(</span>cause<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">ApiException</span><span class="token punctuation">(</span><span class="token class-name">String</span> message<span class="token punctuation">,</span> <span class="token class-name">Throwable</span> cause<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">super</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> cause<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">IErrorCode</span> <span class="token function">getErrorCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> errorCode<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>第二步,新建一个断言处理类 Asserts,简化抛出 ApiException 的步骤。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Asserts</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">fail</span><span class="token punctuation">(</span><span class="token class-name">String</span> message<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ApiException</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">fail</span><span class="token punctuation">(</span><span class="token class-name">IErrorCode</span> errorCode<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ApiException</span><span class="token punctuation">(</span>errorCode<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>第三步,新建一全局异常处理类 GlobalExceptionHandler,对异常信息进行解析,并封装到统一的返回对象 ResultObject 中。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@ControllerAdvice</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">GlobalExceptionHandler</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@ResponseBody</span>
<span class="token annotation punctuation">@ExceptionHandler</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token class-name">ApiException</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">ResultObject</span> <span class="token function">handle</span><span class="token punctuation">(</span><span class="token class-name">ApiException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getErrorCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token class-name">ResultObject</span><span class="token punctuation">.</span><span class="token function">failed</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getErrorCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token class-name">ResultObject</span><span class="token punctuation">.</span><span class="token function">failed</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>全局异常处理类用到了两个注解,<code>@ControllerAdvice</code> 和 <code>@ExceptionHandler</code>。</p><p><code>@ControllerAdvice</code> 是一个特殊的 <code>@Component</code>(可以通过源码看得到),用于标识一个类,这个类中被以下三种注解标识的方法:<code>@ExceptionHandler</code>,<code>@InitBinder</code>,<code>@ModelAttribute</code>,将作用于所有<code>@Controller</code> 类的接口上。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Target</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token class-name">ElementType</span><span class="token punctuation">.</span>TYPE<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span>RUNTIME<span class="token punctuation">)</span>
<span class="token annotation punctuation">@Documented</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">ControllerAdvice</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code>@ExceptionHandler</code> 注解的作用就是标识统一异常处理,它可以指定要统一处理的异常类型,比如说我们自定义的 ApiException。</p><p>第四步,在需要校验的地方通过 Asserts 类抛出异常 ApiException。还拿用户登录这个接口来说明吧。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Controller</span>
<span class="token annotation punctuation">@Api</span><span class="token punctuation">(</span>tags<span class="token operator">=</span><span class="token string">"用户"</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">"/users"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UsersController</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@ApiOperation</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"登录以后返回token"</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"/login"</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token class-name">RequestMethod</span><span class="token punctuation">.</span>POST<span class="token punctuation">)</span>
<span class="token annotation punctuation">@ResponseBody</span>
<span class="token keyword">public</span> <span class="token class-name">ResultObject</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Validated</span> <span class="token class-name">UsersLoginParam</span> users<span class="token punctuation">,</span> <span class="token class-name">BindingResult</span> result<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> token <span class="token operator">=</span> usersService<span class="token punctuation">.</span><span class="token function">login</span><span class="token punctuation">(</span>users<span class="token punctuation">.</span><span class="token function">getUserLogin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> users<span class="token punctuation">.</span><span class="token function">getUserPass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">></span></span> tokenMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation"><</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
tokenMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"token"</span><span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">;</span>
tokenMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"tokenHead"</span><span class="token punctuation">,</span> tokenHead<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token class-name">ResultObject</span><span class="token punctuation">.</span><span class="token function">success</span><span class="token punctuation">(</span>tokenMap<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>该接口需要查询数据库验证密码是否正确,如果密码不正确就抛出校验信息“密码不正确”。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Service</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UsersServiceImpl</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceImpl</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">UsersMapper</span><span class="token punctuation">,</span> <span class="token class-name">Users</span><span class="token punctuation">></span></span> <span class="token keyword">implements</span> <span class="token class-name">IUsersService</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> token <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token comment">//密码需要客户端加密后传递</span>
<span class="token class-name">UserDetails</span> userDetails <span class="token operator">=</span> <span class="token function">loadUserByUsername</span><span class="token punctuation">(</span>username<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>passwordEncoder<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span>password<span class="token punctuation">,</span> userDetails<span class="token punctuation">.</span><span class="token function">getPassword</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Asserts</span><span class="token punctuation">.</span><span class="token function">fail</span><span class="token punctuation">(</span><span class="token string">"密码不正确"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 其他代码省略</span>
<span class="token keyword">return</span> token<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>第五步,通过 ApiPost 来测试一下接口,故意把密码输错。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/springboot/validator-1dd4607e-689a-4ddf-814a-d92ac6408fc3.png" alt=""></p><p>也可以通过 debug 的形式,体验一下整个工作流程。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/springboot/validator-8d673f46-6981-4150-b549-29335bf90cf5.png" alt=""></p><h3 id="三、总结" tabindex="-1"><a class="header-anchor" href="#三、总结" aria-hidden="true">#</a> 三、总结</h3><p>实际开发中把两者结合在一起用,就可以弥补彼此的短板了,简单校验用 Hibernate Validator,复杂一点的逻辑校验,比如说需要数据库查询用全局异常处理来实现。</p><p>为了把 Spring Boot 逻辑校验这块单独拉出来做一个 demo 的例子,我新建了一个 codingmore-validator 的项目,放在 codingmore-learning 项目下面了,想要参考的,直接戳下面的两个链接。</p><p>完整的编程喵整个项目的源码戳第一个,只想看逻辑校验的戳第二个。</p><blockquote><ul><li>编程喵🐱源码地址:<a href="https://github.com/itwanger/coding-more" target="_blank" rel="noopener noreferrer">https://github.com/itwanger/coding-more<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></li><li>codingmore-validator: <a href="https://github.com/itwanger/codingmore-learning/tree/main/codingmore-validator" target="_blank" rel="noopener noreferrer">https://github.com/itwanger/codingmore-learning/tree/main/codingmore-validator<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></li></ul></blockquote><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/springboot/validator-fbd06343-c1ae-4cf6-9b46-bd5c9860b396.png" alt=""></p><p>每个类,每个方法基本上都加了注释,可以很容易就看得懂。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png" alt=""></p></div><!----><footer class="page-meta"><div class="meta-item edit-link"><a href="https://github.com/itwanger/toBeBetterJavaer/edit/master/docs/springboot/validator.md" rel="noopener noreferrer" target="_blank" aria-label="在 GitHub 上编辑此页" class="nav-link label"><!--[--><svg xmlns="http://www.w3.org/2000/svg" class="icon edit-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="edit icon"><path d="M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"></path><path d="M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"></path></svg><!--]-->在 GitHub 上编辑此页<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div><div class="meta-item update-time"><span class="label">上次编辑于: </span><span class="info">2022/6/14 下午2:46:15</span></div><div class="meta-item contributors"><span class="label">贡献者: </span><!--[--><!--[--><span class="contributor" title="email: www.qing_gee@163.com">沉默王二</span><!--]--><!--]--></div></footer><nav class="page-nav"><a href="/springboot/linux-codingmore-run.html" class="nav-link prev" aria-label="一键部署编程喵到生产环境"><div class="hint"><span class="arrow left"></span>上一页</div><div class="link"><!---->一键部署编程喵到生产环境</div></a><!----></nav><div class="giscus-wrapper input-top" style="display:block;">Loading...</div><!----><!--]--></main><!--]--><footer class="footer-wrapper"><div class="footer"><a href="https://beian.miit.gov.cn/" target="_blank">豫ICP备2021038026号-1</a><img src="https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/beian.png" height="15px" width="15px" /><a target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=41030502000411"><span>豫公网安备 41030502000411号</span></a></div><div class="copyright">Copyright © 2022 沉默王二</div></footer><!--]--></div><!--]--><!----><!----><!--]--></div>
<script type="module" src="/assets/app.41bad062.js" defer></script>
</body>
</html>