项目层级
零、register.html / BaseController(v1.1)/ getotp.html(v1.1)
1 <html> 2 <head> 3 <meta charset="UTF-8"> 4 <link rel="stylesheet" href="assets/global/plugins/bootstrap/css/bootstrap.min.css" type="text/css"/> 5 <link rel="stylesheet" href="assets/global/css/components.css" type="text/css"/> 6 <link rel="stylesheet" href="assets/admin/pages/css/login.css" type="text/css"/> 7 <script rel="stylesheet" src="assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script> 8 <link rel="stylesheet" href="selectMeiHua.css"> 9 </head> 10 <body class="login" background="edge_bj_1.jpg"> 11 12 <div class="content"> 13 <h3 class="form-title">用户注册</h3> 14 <div class="form-group"> 15 <label class="control-label">手机号</label> 16 <div> 17 <input type="text" class="form-control" placeholder="手机号" name="telphone" id="telphone"> 18 </div> 19 </div> 20 <div class="form-group"> 21 <label class="control-label">验证码</label> 22 <div> 23 <input type="text" class="form-control" placeholder="验证码" name="otpCode" id="otpCode"> 24 </div> 25 </div> 26 <div class="form-group"> 27 <label class="control-label">用户昵称</label> 28 <div> 29 <input type="text" class="form-control" placeholder="用户昵称" name="name" id="name"> 30 </div> 31 </div> 32 <div class="form-group"> 33 <label class="control-label">性别</label> 34 <div class="select-box"> 35 <input type="text" class="select-input" value="" id="gender" name="gender" placeholder="性别"> 36 <ul class="options-box hide"> 37 <li>男</li> 38 <li>女</li> 39 </ul> 40 </div> 41 </div> 42 <div class="form-group"> 43 <label class="control-label">年龄</label> 44 <div> 45 <input type="text" class="form-control" placeholder="年龄" name="age" id="age"> 46 </div> 47 </div> 48 <div class="form-group"> 49 <label class="control-label">密码</label> 50 <div> 51 <input type="password" class="form-control" placeholder="密码" name="password" id="password"> 52 </div> 53 </div> 54 <div> 55 <button class="btn blue" id="register" type="submit"> 56 注册 57 </button> 58 </div> 59 </div> 60 61 </body> 62 <script> 63 64 jQuery(document).ready(function () { 65 66 //绑定otp的click事件用于向后端发送手机验证码的请求 67 $("#register").on("click", function () { 68 69 var tel = $("#telphone").val(); 70 var name = $("#name").val(); 71 var age = $("#age").val(); 72 var gender = $("#gender").val(); 73 var otpCode = $("#otpCode").val(); 74 var password = $("#password").val(); 75 if (tel == null || tel == '') { 76 alert("用户手机号不能为空"); 77 return false; 78 } 79 if (name == null || name == '') { 80 alert("昵称不能为空"); 81 return false; 82 } 83 if (age == null || age == '') { 84 alert("用户年龄不能为空"); 85 return false; 86 } 87 if (gender == null || gender == '') { 88 alert("用户性别不能为空"); 89 return false; 90 } 91 if (password == null || password == '') { 92 alert("用户密码不能为空"); 93 return false; 94 } 95 if (otpCode == null || otpCode == '') { 96 alert("验证码不能为空"); 97 return false; 98 } 99 $.ajax({ 100 type: "POST", 101 contentType: "application/x-www-form-urlencoded", 102 url: "http://localhost:8080/user/register", 103 data: { 104 "telphone": $("#telphone").val(), 105 "name": $("#name").val(), 106 "age": $("#age").val(), 107 "gender": $("#gender").val(), 108 "otpCode": $("#otpCode").val(), 109 "encrptPassword": $("#password").val(), 110 }, 111 dataType: "json", 112 xhrFields: { 113 withCredentials: true 114 }, 115 crossDomain: true, 116 success: function (result) { 117 118 if (result.status == "success") { 119 alert(result.data) 120 } else { 121 alert("请求失败 原因为:" + result.data.errMsg) 122 } 123 }, 124 error: function (data) { 125 alert("请求失败 原因为:" + data.responseText) 126 } 127 }); 128 }) 129 }) 130 131 window.onload = function () { 132 133 // 判断是否有某个class 134 function hasClass(ele, cls) { 135 return ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)")); 136 } 137 138 // //为指定的dom元素添加样式 139 function addClass(ele, cls) { 140 if (!hasClass(ele, cls)) ele.className += " " + cls; 141 } 142 143 // //删除指定dom元素的样式 144 function removeClass(ele, cls) { 145 if (hasClass(ele, cls)) { 146 var reg = new RegExp("(\\s|^)" + cls + "(\\s|$)"); 147 ele.className = ele.className.replace(reg, " "); 148 } 149 } 150 151 // //如果存在(不存在),就删除(添加)一个样式 152 // function toggleClass(ele, cls) { 153 // if (hasClass(ele, cls)) { 154 // removeClass(ele, cls); 155 // } else { 156 // addClass(ele, cls); 157 // } 158 // } 159 160 document.getElementsByClassName('select-input')[0].onclick = function () { 161 var optionsBox = document.getElementsByClassName('options-box')[0]; 162 var selectInput = document.getElementsByClassName('select-input')[0]; 163 // 这里最好用children,不要用childNode, 否则会有多余的text节点 164 var lis = optionsBox.children; 165 if (hasClass(optionsBox, 'hide')) { // 如果当前不是正在打开选项状态 166 removeClass(optionsBox, 'hide') 167 addClass(selectInput, 'isActive') 168 for (var i = 0; i < lis.length; i++) { 169 if (lis[i].innerHTML == selectInput.value) { // 如果之前已经选择过,将之前的选项激活状态 170 addClass(lis[i], 'active') 171 } else { 172 removeClass(lis[i], 'active') 173 } 174 } 175 } else { 176 addClass(optionsBox, 'hide'); 177 removeClass(selectInput, 'isActive'); 178 } 179 } 180 181 document.getElementsByClassName('options-box')[0].onclick = function (e) { 182 var optionsBox = document.getElementsByClassName('options-box')[0]; 183 var selectInput = document.getElementsByClassName('select-input')[0]; 184 //这一行及下一行是为兼容IE8及以下版本 185 e = e || window.event; 186 var target = e.target || e.srcElement; 187 if (target.tagName.toLowerCase() === "li") { 188 // 将选中的值赋值给展示框文本 189 selectInput.value = target.innerHTML; 190 // 关闭选择列表 191 addClass(optionsBox, 'hide'); 192 // 取消展示框的激活状态 193 removeClass(selectInput, 'isActive'); 194 } 195 } 196 197 // 列表中选项滑过效果 198 document.getElementsByClassName('options-box')[0].onmouseover = function (e) { 199 // 事件代理 200 var optionsBox = document.getElementsByClassName('options-box')[0]; 201 var selectInput = document.getElementsByClassName('select-input')[0]; 202 e = e || window.event; 203 var target = e.target || e.srcElement; 204 if (target.tagName.toLowerCase() === "li") { 205 if (target.innerHTML != selectInput.value) { //如果滑过的不是已经选中的,给予暂时的滑过效果 206 addClass(target, 'active'); 207 } 208 } 209 } 210 211 document.getElementsByClassName('options-box')[0].onmouseout = function (e) { 212 var optionsBox = document.getElementsByClassName('options-box')[0]; 213 var selectInput = document.getElementsByClassName('select-input')[0]; 214 //这一行及下一行是为兼容IE8及以下版本 215 e = e || window.event; 216 var target = e.target || e.srcElement; 217 if (target.tagName.toLowerCase() === "li") { 218 if (target.innerHTML != selectInput.value) { // 如果滑出的不是已经选中的,将滑过的效果取消 219 removeClass(target, 'active'); 220 } 221 } 222 } 223 } 224 225 </script> 226 </html>
1 package com.miaoshaProject.controller; 2 3 import com.miaoshaProject.error.BusinessException; 4 import com.miaoshaProject.error.EnumBusinessError; 5 import com.miaoshaProject.response.CommonReturnType; 6 import org.springframework.http.HttpStatus; 7 import org.springframework.web.bind.annotation.ExceptionHandler; 8 import org.springframework.web.bind.annotation.ResponseBody; 9 import org.springframework.web.bind.annotation.ResponseStatus; 10 11 import javax.servlet.http.HttpServletRequest; 12 import java.util.HashMap; 13 14 /** 15 * @Author wangshuo 16 * @Date 2022/4/14, 11:15 17 * 返回通用错误信息 18 */ 19 public class BaseController { 20 21 public final static String CONTENT_TYPE_FORMED="application/x-www-form-urlencoded"; 22 23 //定义通用的exceptionHandler解决未被Controller吸收的exception 24 @ExceptionHandler(Exception.class) 25 @ResponseStatus(HttpStatus.OK) 26 @ResponseBody 27 public Object handlerException(HttpServletRequest httpServletRequest, Exception e) { 28 29 HashMap<Object, Object> hashMap = new HashMap<>(); 30 if (e instanceof BusinessException) { 31 BusinessException businessException = (BusinessException) e; 32 hashMap.put("errCode", businessException.getErrorCode()); 33 hashMap.put("errMsg", businessException.getErrorMsg()); 34 } else { 35 hashMap.put("errCode", EnumBusinessError.UNKNOWN_ERROR.getErrorCode()); 36 hashMap.put("errMsg", EnumBusinessError.UNKNOWN_ERROR.getErrorMsg()); 37 } 38 return CommonReturnType.create(hashMap, "fail"); 39 } 40 }
<html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="assets/global/plugins/bootstrap/css/bootstrap.min.css" type="text/css"/> <link rel="stylesheet" href="assets/global/css/components.css" type="text/css"/> <link rel="stylesheet" href="assets/admin/pages/css/login.css" type="text/css"/> <script rel="stylesheet" src="assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript"></script> </head> <body class="login" background="edge_bj_1.jpg"> <div class="content"> <h3 class="form-title">用户登录</h3> <div> <label class="control-label">手机号</label> <div class="form-group"> <input type="text" class="form-control" placeholder="手机号" name="telphone" id="telphone"> </div> </div> <div> <button class="btn blue" id="getotp" type="submit"> 获取验证码 </button> </div> </div> </body> <script> jQuery(document).ready(function () { //绑定otp的click事件用于向后端发送手机验证码的请求 $("#getotp").on("click", function () { var tel = $("#telphone").val(); if (tel == null || tel == '') { alert("用户手机号不能为空"); return false; } $.ajax({ type: "POST", contentType: "application/x-www-form-urlencoded", url: "http://localhost:8080/user/getotp", data: { "telphone": $("#telphone").val(), }, dataType: "json", xhrFields: { withCredentials: true }, crossDomain: true, success: function (data) { if (data.status == "success") { alert("验证码已发送至您的手机,请注意查收") alert(data.data) window.location.href = "D:/FirefoxDownLoad/static/register.html"; } else { alert("请求失败 原因为:" + data.data.errorMsg) } }, error: function (data) { alert("请求失败 原因为:" + data.responseText) } }); return false; }) }) </script> </html>
一、pom依赖引入(redis / apache.commons-long3)
1 <!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis --> 2 <dependency> 3 <groupId>org.springframework.session</groupId> 4 <artifactId>spring-session-data-redis</artifactId> 5 <version>2.6.1</version> 6 </dependency> 7 8 <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> 9 <dependency> 10 <groupId>org.springframework.boot</groupId> 11 <artifactId>spring-boot-starter-data-redis</artifactId> 12 <version>2.6.6</version> 13 </dependency> 14 15 <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> 16 <dependency> 17 <groupId>org.apache.commons</groupId> 18 <artifactId>commons-lang3</artifactId> 19 <version>3.12.0</version> 20 </dependency>
application.properties
server.port=8080
#mybatis mapping??
mybatis.mapperLocations=classpath:mapping/*.xml
#MySQL
spring.datasource.name=miaosha
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/miaosha
spring.datasource.username=root
spring.datasource.password=678678
#druid??
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#session????
server.servlet.session.timeout=1
#redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=678678
二、login_config拦截器加跨域请求处理
1.CorsFilter
1 package com.miaoshaProject.login_config; 2 3 import org.springframework.core.Ordered; 4 import org.springframework.core.annotation.Order; 5 import org.springframework.stereotype.Component; 6 7 import javax.servlet.*; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 import java.io.IOException; 11 12 /** 13 * @Description 跨域请求拦截器 14 * @Author rongtao 15 * @Data 2019/4/24 13:32 16 * https://www.codeleading.com/article/4517856247/ 17 */ 18 @Component 19 @Order(Ordered.HIGHEST_PRECEDENCE) 20 public class CorsFilter implements Filter { 21 22 public CorsFilter(){ 23 System.out.println("CorsFilter Constructor..."); 24 } 25 26 @Override 27 public void init(FilterConfig filterConfig) throws ServletException { 28 System.out.println("CorsFilter init..."); 29 } 30 31 @Override 32 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 33 System.out.println("CorsFilter doFilter..."); 34 HttpServletRequest req = (HttpServletRequest) request; 35 HttpServletResponse res = (HttpServletResponse) response; 36 //允许请求携带认证信息(cookie) 37 res.setHeader("Access-Control-Allow-Credentials", "true"); 38 //指定允许其他域名访问 39 res.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin")); 40 //允许请求的类型 41 res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH"); 42 //允许的请求头字段 43 res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 44 //设置预检请求的有效期 45 //浏览器同源策略:出于安全考虑,浏览器限制跨域的http请求。怎样限制呢?通过发送两次请求:预检请求、用户请求。 46 //1、预检请求作用:获知服务器是否允许该跨域请求:如果允许,才发起第二次真实的请求;如果不允许,则拦截第二次请求 47 //2、单位:s,在此期间不用发送预检请求。 48 //3、若为0:表示每次请求都发送预检请求,每个ajax请求之前都会先发送预检请求。 49 res.setHeader("Access-Control-Max-Age", "3600"); 50 //OPTIONS Method表示浏览器发送的预检请求。 51 if ("OPTIONS".equalsIgnoreCase(req.getMethod())) { 52 res.setStatus(HttpServletResponse.SC_OK); 53 } else { 54 chain.doFilter(req, res); 55 } 56 } 57 58 @Override 59 public void destroy() { 60 System.out.println("CorsFilter destroy..."); 61 } 62 }
2.InterceptorConfig
1 package com.miaoshaProject.login_config; 2 3 import com.miaoshaProject.login_config.SessionInterceptor; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 6 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 7 8 /** 9 * @Description WebMvcConfigurerAdapter:扩展mvc 10 * @Author rongtao 11 * @Data 2019/4/24 13:41 12 * https://www.codeleading.com/article/4517856247/ 13 */ 14 @Configuration 15 public class InterceptorConfig extends WebMvcConfigurerAdapter { 16 @Override 17 public void addInterceptors(InterceptorRegistry registry) { 18 //注册登录超时拦截器,并排除拦截登录请求 19 registry.addInterceptor(new SessionInterceptor()).excludePathPatterns("/user/*");//update 20 super.addInterceptors(registry); 21 } 22 }
3.SessionInterceptor(待更新)
1 package com.miaoshaProject.login_config; 2 3 import com.miaoshaProject.dataobject.UserDO; 4 import org.springframework.stereotype.Component; 5 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 6 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import java.io.PrintWriter; 10 11 /** 12 * @Description 登录超时拦截器 13 * @Author rongtao 14 * @Data 2019/4/24 13:37 15 * https://www.codeleading.com/article/4517856247/ 16 */ 17 @Component 18 public class SessionInterceptor extends HandlerInterceptorAdapter { 19 //拦截action 20 @Override 21 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 22 throws Exception { 23 UserDO user = (UserDO) request.getSession().getAttribute("user"); 24 System.out.println(user); 25 //session中User过期 26 if(user == null){ 27 String uri = request.getRequestURI(); 28 System.out.println(uri); 29 //ajax请求响应头会有,x-requested-with 30 if (request.getHeader("x-requested-with") != null && request.getHeader("x-requested-with") 31 .equalsIgnoreCase("XMLHttpRequest")) { 32 //在响应头设置session状态 33 response.setHeader("sessionstatus", "timeout"); 34 response.setHeader("url", uri.substring(0, uri.indexOf("/", 1))); 35 } else { 36 PrintWriter out = response.getWriter(); 37 StringBuilder sb = new StringBuilder(); 38 sb.append("<script type=\"text/javascript\" charset=\"UTF-8\">"); 39 sb.append("alert(\"登录超时,请重新登录\");"); 40 sb.append("window.top.location.href=\""); 41 sb.append("/login.jsp"); 42 sb.append("\";</script>"); 43 out.print(sb.toString()); 44 out.close(); 45 } 46 //返回false不再调用其他的拦截器和处理器 47 return false; 48 } 49 return true; 50 } 51 }
三、EnumBusinessError
1 package com.miaoshaProject.error; 2 3 /** 4 * @Author wangshuo 5 * @Date 2022/4/14, 8:43 6 * 自定义error 7 */ 8 public enum EnumBusinessError implements CommonError{ 9 //10001 参数不合法 10 PARAMETER_VALIDATION_ERROR(10001,"参数不合法"), 11 //20000未知错误 12 UNKNOWN_ERROR(20000,"未知错误"), 13 //以30000开头的错误码代表用户信息错误 14 USER_NOT_EXISTS(30001,"用户不存在"), 15 REGISTER_OTP_ERROR(30002,"验证码错误"), 16 REGISTER_REPEAT(30003,"该手机号已注册账户,请勿重复注册") 17 ; 18 19 private EnumBusinessError(Integer code,String msg){ 20 21 this.errorCode = code; 22 this.errorMsg = msg; 23 } 24 25 private int errorCode; 26 private String errorMsg; 27 28 @Override 29 public int getErrorCode() { 30 return this.errorCode; 31 } 32 33 @Override 34 public String getErrorMsg() { 35 return this.errorMsg; 36 } 37 38 //定制化的方法改动错误信息 39 @Override 40 public CommonError setErrorMsg(String msg) { 41 this.errorMsg = msg; 42 return this; 43 } 44 }
四、UserController
1 //用户注册接口 2 @RequestMapping(value = "/register", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED}) 3 @ResponseBody 4 public CommonReturnType userRegister(@RequestParam(name = "telphone") String telphone, 5 @RequestParam(name = "otpCode") String otpCode, 6 @RequestParam(name = "name") String name, 7 @RequestParam(name = "gender") String gender, 8 @RequestParam(name = "age") Integer age, 9 @RequestParam(name = "encrptPassword") String encrptPassword) throws BusinessException, NoSuchAlgorithmException { 10 11 //验证手机号和对应的optCode是否符合 12 /*String obj = (String)this.httpServletRequest.getSession().getAttribute(telphone);*/ 13 String s = codeMap.get(telphone); 14 15 //用druid类库的equals方法,这个有判空处理 16 /*if (!StringUtils.equals(obj, otpCode)) 17 throw new BusinessException(EnumBusinessError.REGISTER_OTP_ERROR);*/ 18 if (!StringUtils.equals(s, otpCode)) 19 throw new BusinessException(EnumBusinessError.REGISTER_OTP_ERROR); 20 //用户的注册流程 不加构造方法了先,看的清楚点 21 UserModel userModel = new UserModel(); 22 userModel.setAge(age); 23 if (StringUtils.equals(gender, "男")) { 24 userModel.setGender(1); 25 } else { 26 userModel.setGender(2); 27 } 28 userModel.setName(name); 29 userModel.setRegisterMode("byphone"); 30 userModel.setTelpphone(telphone); 31 //md5加密密码 32 userModel.setEncrptPassword(this.encodeByMD5(encrptPassword)); 33 uesrService.register(userModel); 34 return CommonReturnType.create("注册成功,请重新登录"); 35 } 36 37 //用户获取otp短信接口 38 @RequestMapping(value = "/getotp", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED}) 39 @ResponseBody 40 public CommonReturnType getOtp(@RequestParam(name = "telphone") String telphone) { 41 42 //需要按照一定的规则生成otp验证码 43 Random random = new Random(); 44 int randomInt = random.nextInt(89999); 45 randomInt += 10000; 46 String otpCode = String.valueOf(randomInt); 47 //将opt验证码同用户的手机号码关联 使用httpSession的方式绑定他的手机号与optCode 48 /*this.httpServletRequest.getSession().setAttribute(telphone, otpCode);*/ 49 //试试存map 不行就存redis 50 codeMap.put(telphone, otpCode); 51 System.out.println(telphone + " / " + otpCode); 52 //通过短信通道将验证码发送给用户(省略) 53 return CommonReturnType.create(otpCode); 54 }
五、UserServiceImpl
1 @Override 2 @Transactional//保证事务唯一性 3 public void register(UserModel userModel) throws BusinessException { 4 5 if (userModel == null) 6 throw new BusinessException(EnumBusinessError.PARAMETER_VALIDATION_ERROR); 7 if (StringUtils.isEmpty(userModel.getName()) || userModel.getGender() == null || 8 StringUtils.isEmpty(userModel.getTelpphone()) || userModel.getAge() == null || 9 StringUtils.isEmpty(userModel.getRegisterMode())) { 10 11 throw new BusinessException(EnumBusinessError.PARAMETER_VALIDATION_ERROR); 12 } 13 UserDO userDO = convertFromModelObject(userModel); 14 //使用selective 15 //处理用户重复注册异常 16 try { 17 userDOMapper.insertSelective(userDO); 18 }catch (DuplicateKeyException e){ 19 throw new BusinessException(EnumBusinessError.REGISTER_REPEAT); 20 } 21 22 //把刚刚新增成功的userId赋值给UserPasswordDO用于密码表的新增 23 userModel.setId(userDO.getId()); 24 UserPasswordDO userPasswordDO = convertPasswordFromModelObject(userModel); 25 userPasswordDOMapper.insertSelective(userPasswordDO); 26 } 27 28 private UserPasswordDO convertPasswordFromModelObject(UserModel userModel) { 29 30 if (userModel == null) 31 return null; 32 UserPasswordDO userPasswordDO = new UserPasswordDO(); 33 userPasswordDO.setUserId(userModel.getId()); 34 userPasswordDO.setEncrptPassword(userModel.getEncrptPassword()); 35 return userPasswordDO; 36 } 37 38 private UserDO convertFromModelObject(UserModel userModel) { 39 40 if (userModel == null) { 41 return null; 42 } 43 UserDO userDO = new UserDO(); 44 BeanUtils.copyProperties(userModel, userDO); 45 return userDO; 46 }
六、UserDOMapper(keyProperty / useGenderateKeys)
<insert id="insertSelective" parameterType="com.miaoshaProject.dataobject.UserDO" keyProperty="id" useGeneratedKeys="true"> <!-- WARNING - @mbg.generated This element is automatically generated by MyBatis Generator, do not modify. This element was generated on Thu Apr 14 10:32:50 CST 2022. --> insert into user_info <trim prefix="(" suffix=")" suffixOverrides=","> <if test="id != null"> id, </if> <if test="name != null"> name, </if> <if test="gender != null"> gender, </if> <if test="age != null"> age, </if> <if test="telpphone != null"> telpphone, </if> <if test="registerMode != null"> register_mode, </if> <if test="thirdPartyId != null"> third_party_id, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="id != null"> #{id,jdbcType=INTEGER}, </if> <if test="name != null"> #{name,jdbcType=VARCHAR}, </if> <if test="gender != null"> #{gender,jdbcType=INTEGER}, </if> <if test="age != null"> #{age,jdbcType=INTEGER}, </if> <if test="telpphone != null"> #{telpphone,jdbcType=VARCHAR}, </if> <if test="registerMode != null"> #{registerMode,jdbcType=VARCHAR}, </if> <if test="thirdPartyId != null"> #{thirdPartyId,jdbcType=VARCHAR}, </if> </trim> </insert>
七、sql
ALTER TABLE `miaosha`.`user_info` ADD UNIQUE INDEX `telphone_unique_index`(`telpphone`) USING BTREE COMMENT '给手机号添加唯一索引,确保一个手机号只能注册一个用户';
本文来自博客园,作者:荣慕平,转载请注明原文链接:https://www.cnblogs.com/rongmuping/articles/16151476.html