当前位置: 首页 > news >正文

Spring Boot快速搭建一个简易商城项目【完成登录功能且优化】

完成登录且优化:

未优化做简单的判断:

全部异常抓捕

优化:返回的是json的格式

BusinessException:所有的错误放到这个容器中,全局异常从这个类中调用

BusinessException:
package com.lya.lyaspshop.exception;import com.lya.lyaspshop.resp.JsonResponseStatus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;@EqualsAndHashCode(callSuper = true)//自动生成equals和hashCode方法
@AllArgsConstructor//自动生成全参构造函数
@NoArgsConstructor//自动生成无参构造函数
@Data//自动生成getters、setters、toString
public class BusinessException extends RuntimeException {//    所有的错误放到这个容器中,全局异常从这个类中调用private JsonResponseStatus jsonResponseStatus;}

GlobalExceptionHandler

package com.lya.lyaspshop.exception;import com.lya.lyaspshop.resp.JsonResponseBody;
import com.lya.lyaspshop.resp.JsonResponseStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice//用于声明这个类是一个全局异常处理器
@Slf4j
public class GlobalExceptionHandler {//    已知错误@ExceptionHandler(BusinessException.class)//声明这是一个异常处理方法public JsonResponseBody<?> exceptionBusinessException(BusinessException e) {JsonResponseStatus status = e.getJsonResponseStatus();log.info(status.getMsg());//使用日志打印异常的消息。return JsonResponseBody.other(status);}//    未知错误@ExceptionHandler(Throwable.class)public JsonResponseBody<?> exceptionThrowable(Throwable e) {log.info(e.getMessage());//使用日志打印异常的消息。return JsonResponseBody.other(JsonResponseStatus.UN_KNOWN);}
}

这里为啥要写这两个类:

理解:编写 GlobalExceptionHandler 类可以集中处理应用程序中的各种异常,提高代码的可维护性,同时简化了代码

jsr303

//这里体现了为啥要建这个类:1.降低代码耦合度:VO 实体类可以将数据从数据库实体类中解耦           2.用户进行权限校验等操作,业务逻辑与数据访问层分离开来,提高代码的可读性和可维护性
如果我直接在数据库的实体类中去

<!-- jsr303 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

实体:使用注解

@NotBlank

抛一个异常:

报错信息:

这个是时候错误已经该变:

连接日志查看:

遇到一个问题:这里就是异常就是使用的303自己带的异常,不要写其他的

前后台的加密过程:

从前台发送请求来:

引入加密js

		<script src="http://www.gongjuji.net/Content/files/jquery.md5.js" type="text/javascript"></script>

加密成功:

加密后数据库的原密码肯定是不对的了。这我们使用debug给截取到密码存入数据库中。

集成redis

<!--        redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

RedisServiceImpl 

package com.lya.lyaspshop.service.impl;import com.lya.lyaspshop.pojo.User;
import com.lya.lyaspshop.service.IRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class RedisServiceImpl implements IRedisService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;//    往redis设置@Overridepublic void setUserToRedis(String token, User user) {redisTemplate.opsForValue().set("user:" + token, user, 7200, TimeUnit.SECONDS);}@Overridepublic User getUserByToken(String token) {return (User) redisTemplate.opsForValue().get("user:" + token);}}

IRedisService

package com.lya.lyaspshop.service;import com.lya.lyaspshop.pojo.User;public interface IRedisService {/*** 将登陆User对象保存到Redis中,并以Token为键*/void setUserToRedis(String token, User user);/*** 根据token令牌获取redis中存储的user对象*/User getUserByToken(String token);}

redisService.setUserToRedis(token, one);

加入cookie

使用CookieUtils类:

package com.lya.lyaspshop.utils;import lombok.extern.slf4j.Slf4j;import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;@Slf4j
public class CookieUtils {/*** @Description: 得到Cookie的值, 不编码*/public static String getCookieValue(HttpServletRequest request, String cookieName) {return getCookieValue(request, cookieName, false);}/*** @Description: 得到Cookie的值*/public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {Cookie[] cookieList = request.getCookies();if (cookieList == null || cookieName == null) {return null;}String retValue = null;try {for (int i = 0; i < cookieList.length; i++) {if (cookieList[i].getName().equals(cookieName)) {if (isDecoder) {retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");} else {retValue = cookieList[i].getValue();}break;}}} catch (UnsupportedEncodingException e) {e.printStackTrace();}return retValue;}/*** @Description: 得到Cookie的值*/public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {Cookie[] cookieList = request.getCookies();if (cookieList == null || cookieName == null) {return null;}String retValue = null;try {for (int i = 0; i < cookieList.length; i++) {if (cookieList[i].getName().equals(cookieName)) {retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);break;}}} catch (UnsupportedEncodingException e) {e.printStackTrace();}return retValue;}/*** @Description: 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码*/public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,String cookieValue) {setCookie(request, response, cookieName, cookieValue, -1);}/*** @param request* @param response* @param cookieName* @param cookieValue* @param cookieMaxage* @Description: 设置Cookie的值 在指定时间内生效,但不编码*/public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,String cookieValue, int cookieMaxage) {setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);}/*** @Description: 设置Cookie的值 不设置生效时间,但编码* 在服务器被创建,返回给客户端,并且保存客户端* 如果设置了SETMAXAGE(int seconds),会把cookie保存在客户端的硬盘中* 如果没有设置,会默认把cookie保存在浏览器的内存中* 一旦设置setPath():只能通过设置的路径才能获取到当前的cookie信息*/public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,String cookieValue, boolean isEncode) {setCookie(request, response, cookieName, cookieValue, -1, isEncode);}/*** @Description: 设置Cookie的值 在指定时间内生效, 编码参数*/public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,String cookieValue, int cookieMaxage, boolean isEncode) {doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);}/*** @Description: 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)*/public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,String cookieValue, int cookieMaxage, String encodeString) {doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);}/*** @Description: 删除Cookie带cookie域名*/public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,String cookieName) {doSetCookie(request, response, cookieName, null, -1, false);}/*** @Description: 设置Cookie的值,并使其在指定时间内生效*/private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {try {if (cookieValue == null) {cookieValue = "";} else if (isEncode) {cookieValue = URLEncoder.encode(cookieValue, "utf-8");}Cookie cookie = new Cookie(cookieName, cookieValue);if (cookieMaxage > 0)cookie.setMaxAge(cookieMaxage);if (null != request) {// 设置域名的cookieString domainName = getDomainName(request);log.info("========== domainName: {} ==========", domainName);if (!"localhost".equals(domainName)) {cookie.setDomain(domainName);}}cookie.setPath("/");response.addCookie(cookie);} catch (Exception e) {e.printStackTrace();}}/*** @Description: 设置Cookie的值,并使其在指定时间内生效*/private static void doSetCookie(HttpServletRequest request, HttpServletResponse response,String cookieName, String cookieValue, int cookieMaxage, String encodeString) {try {if (cookieValue == null) {cookieValue = "";} else {cookieValue = URLEncoder.encode(cookieValue, encodeString);}Cookie cookie = new Cookie(cookieName, cookieValue);if (cookieMaxage > 0)cookie.setMaxAge(cookieMaxage);if (null != request) {// 设置域名的cookieString domainName = getDomainName(request);log.info("========== domainName: {} ==========", domainName);if (!"localhost".equals(domainName)) {cookie.setDomain(domainName);}}cookie.setPath("/");response.addCookie(cookie);} catch (Exception e) {e.printStackTrace();}}/*** @Description: 得到cookie的域名*/private static String getDomainName(HttpServletRequest request) {String domainName = null;String serverName = request.getRequestURL().toString();if (serverName == null || serverName.equals("")) {domainName = "";} else {serverName = serverName.toLowerCase();serverName = serverName.substring(7);final int end = serverName.indexOf("/");serverName = serverName.substring(0, end);if (serverName.indexOf(":") > 0) {String[] ary = serverName.split("\\:");serverName = ary[0];}final String[] domains = serverName.split("\\.");int len = domains.length;if (len > 3 && !isIp(serverName)) {// www.xxx.com.cndomainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];} else if (len <= 3 && len > 1) {// xxx.com or xxx.cndomainName = "." + domains[len - 2] + "." + domains[len - 1];} else {domainName = serverName;}}return domainName;}public static String trimSpaces(String IP) {//去掉IP字符串前后所有的空格while (IP.startsWith(" ")) {IP = IP.substring(1, IP.length()).trim();}while (IP.endsWith(" ")) {IP = IP.substring(0, IP.length() - 1).trim();}return IP;}public static boolean isIp(String IP) {//判断是否是一个IPboolean b = false;IP = trimSpaces(IP);if (IP.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) {String s[] = IP.split("\\.");if (Integer.parseInt(s[0]) < 255)if (Integer.parseInt(s[1]) < 255)if (Integer.parseInt(s[2]) < 255)if (Integer.parseInt(s[3]) < 255)b = true;}return b;}}

自定义注解

根据@isNoblank去写:

这三行代码必须写的:

    boolean require() default false;String expr() default "";String message() default "";

IsMobile
package com.lya.lyaspshop.core;import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;@Documented
@Constraint(validatedBy = {IsMobileConstraintValidator.class})
@Target({FIELD})
@Retention(RUNTIME)
public @interface IsMobile {boolean require() default false;String expr() default "";String message() default "";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}

IsMobileConstraintValidator 

package com.lya.lyaspshop.core;import com.baomidou.mybatisplus.core.toolkit.StringUtils;import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;/*** @author CloudJun*/
public class IsMobileConstraintValidator implements ConstraintValidator<IsMobile, String> {private boolean require;private String expr;@Overridepublic void initialize(IsMobile isMobile) {expr = isMobile.expr();require = isMobile.require();}@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {if (!require) return true;if (StringUtils.isEmpty(value)) return false;return value.matches(expr);}}

优化:定义一个常量类(使用的定值往这里调用就行)

package com.lya.lyaspshop.core;public abstract class Constants {//    常类public static final String EXPR_MOBILE = "(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}";public static final String EXPR_PASSWORD = "[a-zA-Z0-9]{32}";public static final String USER_TOKEN_PREFIX = "user:";}

相关文章:

Spring Boot快速搭建一个简易商城项目【完成登录功能且优化】

完成登录且优化&#xff1a; 未优化做简单的判断&#xff1a; 全部异常抓捕 优化&#xff1a;返回的是json的格式 BusinessException&#xff1a;所有的错误放到这个容器中&#xff0c;全局异常从这个类中调用 BusinessException&#xff1a; package com.lya.lyaspshop.exce…...

KG+LLM(一)KnowGPT: Black-Box Knowledge Injection for Large Language Models

论文链接&#xff1a;2023.12-https://arxiv.org/pdf/2312.06185.pdf 1.Background & Motivation 目前生成式的语言模型&#xff0c;如ChatGPT等在通用领域获得了巨大的成功&#xff0c;但在专业领域&#xff0c;由于缺乏相关事实性知识&#xff0c;LLM往往会产生不准确的…...

使用anaconda创建爬虫spyder工程

1.由于每个工程使用的环境都可能不一样&#xff0c;因此一个好的习惯就是不同的工程都创建属于自己的环境&#xff0c;在anaconda中默认的环境是base&#xff0c;我们现在来创建一个名为spyder的环境&#xff0c;专门用于爬虫工程&#xff1a; //括号中名字&#xff0c;代表当…...

网络通信(7)-TCP协议解析

目录 一、定义 二、主要特点 三、报文格式 四、工作方式...

win32 WM_MENUSELECT消息学习

之前写了一些win32的程序&#xff0c;处理菜单单击都是处理WM_COMMAND消息&#xff0c;通过 LOWORD(wParam) 获取菜单ID&#xff0c;判断单击的是哪个菜单项&#xff1b; 还有一些其他菜单消息&#xff1b; 当在菜单项中移动光标或鼠标&#xff0c;程序会收到许多WM_MENUSELEC…...

Java学习苦旅(十六)——List

本篇博客将详细讲解Java中的List。 文章目录 预备知识——初识泛型泛型的引入泛型小结 预备知识——包装类基本数据类型和包装类直接对应关系装包与拆包 ArrayList简介ArrayList使用ArrayList的构造ArrayList常见操作ArrayList遍历 结尾 预备知识——初识泛型 泛型的引入 我…...

python爬虫实现获取招聘信息

使用的python版本&#xff1a; 3.12.1 selenium版本&#xff1a;4.8.0 urllib版本&#xff1a;1.26.18 from selenium import webdriver from selenium.webdriver import ActionChains import timeimport re import xlwt import urllib.parsedef get_html(url):chrome_drive…...

模块电源(七):LDO 应用

1、Typical application circuit LDO 典型应用电路如下图所示&#xff1a; 2、High Output Current Positive Voltage Regulator 通过 PNP 型三极管 Tr1 &#xff0c;可以提高 LDO 的输出电流能力&#xff0c;电路如下图所示&#xff1a; 设流过 R1 的电流为 &#xff0c;当 …...

Redis命令---Hash(哈希)篇 (超全)

目录 1.Redis Hmset 命令 - 同时将多个 field-value (域-值)对设置到哈希表 key 中。简介语法可用版本: > 2.0.0返回值: 如果命令执行成功&#xff0c;返回 OK 。 示例 2.Redis Hmget 命令 - 获取所有给定字段的值简介语法可用版本: > 2.0.0返回值: 一个包含多个给定字段…...

Objects are not valid as a React child (found: object with keys {name}).

在jsx中可以嵌套表达式&#xff0c;将表达式作为内容的一部分&#xff0c;但是要注意&#xff0c;普通对象不能作为子元素&#xff1b;但是数组&#xff0c;react元素对象是可以的 如下&#xff1a;不能将stu这个对象作为子元素放 function App() {const myCal imgStyleconst…...

nodejs业务分层如何写后端接口

这里展示的是在node express 项目中的操作 &#xff0c;数据库使用的是MongoDB&#xff0c;前期关于express和MongoDB的文章可访问&#xff1a; Nodejs后端express框架 server后端接口操作&#xff1a;通过路由匹配——>调用对应的 Controller——>进行 Service调用——&…...

Windows 7 虚拟机的安装以及解决安装VMVMware tools问题

1.Windows 7 虚拟机的安装以及解决安装VMVMware tools问题 参考&#xff1a;Windows 7 虚拟机的安装以及解决安装VMVMware tools问题 注意&#xff1a;下载官方补丁&#xff1a;Microsoft Update Catalog在智慧联想浏览器中打不开&#xff0c;要在火狐中才能打开下载。 2.win7如…...

[足式机器人]Part2 Dr. CAN学习笔记-自动控制原理Ch1-9PID控制器

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-自动控制原理Ch1-9PID控制器&#xff09; P —— Proportional I —— Integral D —— Derivative 当前误差/过去误差/误差的变化趋势 K p ⋅ e K_{\mathrm{p}}\cdot e Kp​⋅e&#xff1a;比…...

SSM养老院综合服务系统----计算机毕业设计

项目介绍 该项目为后台管理项目&#xff0c;分为管理员与护工两种角色&#xff1b; 管理员角色包含以下功能&#xff1a; 管理员登录,个人资料密码管理,用户管理,床位类型管理,床位管理,护工管理,老人管理,咨询登记管理,预约登记管理,老人健康信息管理,费用管理等功能。 护…...

广州求职招聘(找工作)去哪里找比较好

在广州找工作&#xff0c;可以选择“吉鹿力招聘网”这个平台。它是一个号称直接和boss聊的互联网招聘神器&#xff0c;同时&#xff0c;“吉鹿力招聘网”作岗位比较齐全&#xff0c;企业用户也多&#xff0c;比较全面。在“吉鹿力招聘网”历即可投递岗位。 广州找工作上 吉鹿力…...

ARM NEON 指令

NEON指令 按照操作数类型可以分为正常指令、宽指令、窄指令、饱和指令、长指令。 正常指令&#xff1a;生成大小相同且类型通常与操作数向量相同到结果向量。长指令&#xff1a;对双字向量操作数执行运算&#xff0c;生产四字向量到结果。所生成的元素一般是操作数元素宽度到…...

Open3D 最小二乘拟合平面——拉格朗日乘子法

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接Open3D 最小二乘拟合平面——拉格朗日乘子法。爬虫自重。 一、算法原理 设拟合出的平面方程为: a x + b y +...

Rockchip平台Android应用预安装功能(基于Android13)

Rockchip平台Android应用预安装功能(基于Android13) 1. 预安装应用类型 Android上的应用预安装功能&#xff0c;主要是指配置产品时&#xff0c;根据厂商要求&#xff0c;将事先准备好的第三方应用预置进Android系统。预安装分为以下几种类型&#xff1a; 安装不可卸载应用安…...

vue项目表单使用正则过滤ip、手机号

import useFormValidate from /hooks/useFormValidatesetup(props, { emit }) {const { validateName, validateIPAndPort } useFormValidate()const state reactive({workFaceInfo: props.info?.id ? props.info : {},sysTypeData: props.sysType,formRules: {name: [{req…...

vscode编译调试sln工程

使用msvc工具链 vscode配置调用visual studio的编译和调试环境_vscode用vs-CSDN博客 将vscode打造无敌的IDE(14) tasks.json和launch.json配置详解&#xff0c;随心所欲添加自动化任务_tasks.json详解-CSDN博客 通过命令行使用 Microsoft C 工具集 | Microsoft Learn 编译…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...