前端项目nginx部署
nginx配置文件
worker_processes 1;events {worker_connections 1024;
}http {include mime.types;default_type application/json;sendfile on;keepalive_timeout 65;server {listen 8080;server_name localhost;# 指定前端项目所在的位置location / {root html/hmdp;index index.html index.htm;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}location /api { default_type application/json;#internal; keepalive_timeout 30s; keepalive_requests 1000; #支持keep-alive proxy_http_version 1.1; rewrite /api(/.*) $1 break; proxy_pass_request_headers on;#more_clear_input_headers Accept-Encoding; proxy_next_upstream error timeout; proxy_pass http://127.0.0.1:8081;#proxy_pass http://backend;}}upstream backend {server 127.0.0.1:8081 max_fails=5 fail_timeout=10s weight=1;#server 127.0.0.1:8082 max_fails=5 fail_timeout=10s weight=1;}
}
启动nginx
在D:\centos7nginx\nginx-1.18.0\nginx-1.18.0目录下,执行start nginx.exe命令启动。
可以看出,地址http://localhost:8080/api请求 会转发到 http://localhost:8081上
例如:http://localhost:8080/api/shop-type/list 会转发到 http://localhost:8081/shop-type/list
正则表达式校验的工具类
package com.xkj.org.utils;/*** @author 虎哥*/
public abstract class RegexPatterns {/*** 手机号正则*/public static final String PHONE_REGEX = "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";/*** 邮箱正则*/public static final String EMAIL_REGEX = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";/*** 密码正则。4~32位的字母、数字、下划线*/public static final String PASSWORD_REGEX = "^\\w{4,32}$";/*** 验证码正则, 6位数字或字母*/public static final String VERIFY_CODE_REGEX = "^[a-zA-Z\\d]{6}$";}
package com.xkj.org.utils;import cn.hutool.core.util.StrUtil;/*** @author 虎哥*/
public class RegexUtils {/*** 是否是无效手机格式* @param phone 要校验的手机号* @return true:符合,false:不符合*/public static boolean isPhoneInvalid(String phone){return mismatch(phone, RegexPatterns.PHONE_REGEX);}/*** 是否是无效邮箱格式* @param email 要校验的邮箱* @return true:符合,false:不符合*/public static boolean isEmailInvalid(String email){return mismatch(email, RegexPatterns.EMAIL_REGEX);}/*** 是否是无效验证码格式* @param code 要校验的验证码* @return true:符合,false:不符合*/public static boolean isCodeInvalid(String code){return mismatch(code, RegexPatterns.VERIFY_CODE_REGEX);}// 校验是否不符合正则格式private static boolean mismatch(String str, String regex){if (StrUtil.isBlank(str)) {return true;}return !str.matches(regex);}
}
登录校验用户状态
因为很多功能都要校验用户,所以需要使用拦截器。
拦截器校验了用户信息,将用户信息放入每一个线程的ThreadLocal中,每个线程需要用户信息就从自己的ThreadLocal中获取,保证的线程安全。
拦截器
package com.xkj.org.interceptor;import com.xkj.org.entity.User;
import com.xkj.org.utils.UserHolder;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {//1.获取session中的userUser user = (User)request.getSession().getAttribute("user");//2.判断用户是否存在if (user == null) {//3.不存在,拦截, 401未授权response.setStatus(401);return false;}//4.存在,保存用户信息到ThreadLocalUserHolder.saveUser(user);//5.放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {//请求执行完毕,释放内存,threadlocal避免内存泄漏UserHolder.removeUser();}
}
ThreadLocal
package com.xkj.org.utils;import com.xkj.org.entity.User;public class UserHolder {private static final ThreadLocal<User> t1 = new ThreadLocal<>();public static void saveUser(User user) {t1.set(user);}public static User getUser() {return t1.get();}public static void removeUser() {t1.remove();}
}
配置拦截器
package com.xkj.org.config;import com.xkj.org.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MvcConfig implements WebMvcConfigurer{@Overridepublic void addInterceptors(InterceptorRegistry registry) {//添加拦截器,排除一些不需要拦截的urlregistry.addInterceptor(new LoginInterceptor()).excludePathPatterns("/user/code","/user/login","/blog/hot","/shop/**","/shop-type/**","/upload/**","voucher/**");}
}
用户相关功能
发送验证码
登录用户
获取用户信息
package com.xkj.org.controller;import com.xkj.org.dto.LoginFormDTO;
import com.xkj.org.dto.Result;
import com.xkj.org.entity.User;
import com.xkj.org.service.IUserService;
import com.xkj.org.utils.UserHolder;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpSession;@RequestMapping("/user")
@RestController
public class UserController {@Resourceprivate IUserService userService;@PostMapping("/code")public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {return userService.sendCode(phone, session);}@PostMapping("/login")public Result login(@RequestBody LoginFormDTO loginFormDTO, HttpSession session) {return userService.login(loginFormDTO, session);}@GetMapping("/me")public Result me() {User user = UserHolder.getUser();return Result.ok(user);}
}
package com.xkj.org.service.impl;import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xkj.org.dto.LoginFormDTO;
import com.xkj.org.dto.Result;
import com.xkj.org.entity.User;
import com.xkj.org.mapper.UserMapper;
import com.xkj.org.service.IUserService;
import com.xkj.org.utils.RegexUtils;
import com.xkj.org.utils.SystemConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpSession;@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{@Overridepublic Result sendCode(String phone, HttpSession session) {//检验手机号if (RegexUtils.isPhoneInvalid(phone)) {return Result.fail("手机号无效");}//生成验证码String code = RandomUtil.randomString(6);//存入sessionsession.setAttribute("code", code);//发送验证码给用户log.info("给用户发送验证码============={}", code);//返回return Result.ok("发送成功");}@Overridepublic Result login(LoginFormDTO loginFormDTO, HttpSession session) {//校验手机号if (RegexUtils.isPhoneInvalid(loginFormDTO.getPhone())) {return Result.fail("手机号无效");}//校验验证码String cacheCode = session.getAttribute("code").toString();String code = session.getAttribute("code").toString();if (code == null || !code.equals(cacheCode)) {return Result.fail("验证码错误");}//根据手机号查询用户User user = query().eq("phone", loginFormDTO.getPhone()).one();if (user == null) {//用户不存在则创建用户user = createUser(loginFormDTO.getPhone());}//将用户放入sessionsession.setAttribute("user", user);//返回return Result.ok();}private User createUser(String phone) {User user = new User();user.setPhone(phone);user.setNickName(SystemConstants.USER_NICK_NAME_PREFIX + RandomUtil.randomString(6));save(user);return user;}
}