目录
4.首页访问 ,导入前端页面及页面对应的js/css/images文件
2)使用Mybatis-plus反向生成代码(Goods商品信息)
3)创建IndexController并定义商品查询请求处理方法
1.1)构建UserDto,定义mobile和password属性
1.3)定义userLogin(UserDto userDto,HttpServletRequest req,HttpServletResponse resp)
1.4)定义响应封装类JsonResponseBody和JsonResponseStatus
1.5)在IUserService中定义userLogin(UserVo userVo),并返回JsonResponseBody
前端:Freemarker、jQuery
后端:SpringBoot、MyBatisPlus、Lombok
中间件:Redis
用户表:t_user
商品表:t_goods
订单表:t_order
订单项表:t_order_item
数据源表:t_dict_type
数据项表:t_dict_data

后续微服务秒杀项目所用:
秒杀商品表:t_seckill_goods
秒杀订单表:t_seckill_order
起初搭建时,可以不勾选任何组件
pom依赖:
- "1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0modelVersion>
- <parent>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-parentartifactId>
- <version>2.3.9.RELEASEversion>
- <relativePath/>
- parent>
- <groupId>com.ycxgroupId>
- <artifactId>spbootproartifactId>
- <version>0.0.1-SNAPSHOTversion>
- <name>spbootproname>
- <description>Demo project for Spring Bootdescription>
-
- <properties>
- <java.version>1.8java.version>
- properties>
- <dependencies>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-freemarkerartifactId>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
-
-
- <dependency>
- <groupId>mysqlgroupId>
- <artifactId>mysql-connector-javaartifactId>
- <scope>runtimescope>
- <version>5.1.44version>
- dependency>
-
-
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <optional>trueoptional>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- <exclusions>
- <exclusion>
- <groupId>org.junit.vintagegroupId>
- <artifactId>junit-vintage-engineartifactId>
- exclusion>
- exclusions>
- dependency>
-
- <dependency>
- <groupId>junitgroupId>
- <artifactId>junitartifactId>
- <scope>testscope>
- dependency>
-
-
- <dependency>
- <groupId>com.baomidougroupId>
- <artifactId>mybatis-plus-boot-starterartifactId>
- <version>3.4.0version>
- dependency>
-
- <dependency>
- <groupId>com.baomidougroupId>
- <artifactId>mybatis-plus-generatorartifactId>
- <version>3.4.0version>
- dependency>
-
-
- <dependency>
- <groupId>com.zaxxergroupId>
- <artifactId>HikariCPartifactId>
- dependency>
-
-
- <dependency>
- <groupId>commons-codecgroupId>
- <artifactId>commons-codecartifactId>
- dependency>
-
- <dependency>
- <groupId>org.apache.commonsgroupId>
- <artifactId>commons-lang3artifactId>
- <version>3.6version>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-validationartifactId>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-data-redisartifactId>
- dependency>
-
-
- <dependency>
- <groupId>org.apache.commonsgroupId>
- <artifactId>commons-pool2artifactId>
- dependency>
-
-
-
- <dependency>
- <groupId>com.alipay.sdkgroupId>
- <artifactId>alipay-easysdkartifactId>
- <version>2.0.1version>
- dependency>
- dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-maven-pluginartifactId>
- plugin>
- plugins>
- build>
-
- project>
1)添加数据库及连接池配置
2)添加freemarker配置
3)添加mybatis-plus配置
4)添加logging日志配置
yml文件:
- server:
- port: 8081
- servlet:
- context-path: /
- spring:
- datasource:
- url: jdbc:mysql://localhost:3306/spbootpro?useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&characterEncoding=UTF8
- driver-class-name: com.mysql.jdbc.Driver
- password: 1234
- username: root
- hikari:
- # 最小空闲连接数量
- minimum-idle: 5
- # 空闲连接存活最大时间,默认600000(10分钟)
- idle-timeout: 180000
- # 连接池最大连接数,默认是10
- maximum-pool-size: 10
- # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
- auto-commit: true
- # 连接池名称
- pool-name: MyHikariCP
- # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
- max-lifetime: 1800000
- # 数据库连接超时时间,默认30秒,即30000
- connection-timeout: 30000
- freemarker:
- #设置编码格式
- charset: UTF-8
- #后缀
- suffix:
- #文档类型
- content-type: text/html
- #模板前端
- template-loader-path: classpath:/templates/
- #启用模板
- enabled: true
- mvc:
- static-path-pattern: /static/**
- redis:
- #服务端IP
- host: 192.168.122.128
- #端口
- port: 6379
- #密码
- password: 123456
- #选择数据库
- database: 9
- #超时时间
- timeout: 10000ms
- #Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问
- #Lettuce线程安全,Jedis线程非安全
- lettuce:
- pool:
- #最大连接数,默认8
- max-active: 8
- #最大连接阻塞等待时间,默认-1
- max-wait: 10000ms
- #最大空闲连接,默认8
- max-idle: 200
- #最小空闲连接,默认0
- min-idle: 5
- #mybatis-plus配置
- mybatis-plus:
- #所对应的 XML 文件位置
- mapper-locations: classpath*:/mapper/*Mapper.xml
- #别名包扫描路径
- type-aliases-package: com.ycx.spbootpro.model
- configuration:
- #驼峰命名规则
- map-underscore-to-camel-case: true
- #日志配置
- logging:
- level:
- com.ycx.spbootpro.mapper: debug
- package com.ycx.spbootpro;
-
- import org.mybatis.spring.annotation.MapperScan;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.transaction.annotation.EnableTransactionManagement;
-
- @MapperScan({"com.ycx.spbootpro.mapper"})
- @EnableTransactionManagement
- @SpringBootApplication
- public class SpbootproApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(SpbootproApplication.class, args);
- }
-
- }

IndexController :
- package com.ycx.spbootpro.controller;
-
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
-
- /**
- * @author 杨总
- * @create 2022-11-04 21:02
- */
- @Controller
- public class IndexController {
- @RequestMapping("/")
- public String index(){
- // 前缀+逻辑视图名+后缀
- return "index.html";
- }
- }
运行访问:


RedisConfig :
- package com.ycx.spbootpro.config;
-
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.data.redis.connection.RedisConnectionFactory;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
-
- @Configuration
- public class RedisConfig {
-
- @Bean
- public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
- RedisTemplate<String,Object> redisTemplate=new RedisTemplate<>();
- redisTemplate.setStringSerializer(new StringRedisSerializer());
- redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
- redisTemplate.setHashKeySerializer(new StringRedisSerializer());
- redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
- redisTemplate.setConnectionFactory(connectionFactory);
- redisTemplate.afterPropertiesSet();
- return redisTemplate;
- }
- }
BusinessException :
- package com.ycx.spbootpro.exception;
-
- import com.ycx.spbootpro.utils.JsonResponseStatus;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class BusinessException extends RuntimeException {
- private JsonResponseStatus jsonResponseStatus;
- }
GlobalExceptionHandler :
- package com.ycx.spbootpro.exception;
-
- import com.ycx.spbootpro.utils.JsonResponseBody;
- import com.ycx.spbootpro.utils.JsonResponseStatus;
- import org.springframework.validation.BindException;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.RestControllerAdvice;
-
- @RestControllerAdvice
- public class GlobalExceptionHandler {
-
- @ExceptionHandler
- public JsonResponseBody> exceptionHandler(Exception e){
- JsonResponseBody> jsonResponseBody=null;
- e.printStackTrace();
- if(e instanceof BusinessException){
- BusinessException ex= (BusinessException) e;
- jsonResponseBody=new JsonResponseBody<>(ex.getJsonResponseStatus());
- }else if(e instanceof BindException){
- BindException ex= (BindException) e;
- String msg = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();
- jsonResponseBody=new JsonResponseBody<>(JsonResponseStatus.BIND_ERROR);
- jsonResponseBody.setMsg(msg);
- }else{
- System.out.println("aaaaaa");
- }
- return jsonResponseBody;
- }
- }
CodeGenerator :
- package com.ycx.spbootpro.generator;
-
- import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
- import com.baomidou.mybatisplus.core.toolkit.StringPool;
- import com.baomidou.mybatisplus.core.toolkit.StringUtils;
- import com.baomidou.mybatisplus.generator.AutoGenerator;
- import com.baomidou.mybatisplus.generator.InjectionConfig;
- import com.baomidou.mybatisplus.generator.config.*;
- import com.baomidou.mybatisplus.generator.config.po.TableInfo;
- import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
- import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Scanner;
-
- public class CodeGenerator {
-
- /**
- *
- * 读取控制台内容
- *
- */
- public static String scanner(String tip) {
- Scanner scanner = new Scanner(System.in);
- StringBuilder help = new StringBuilder();
- help.append("请输入" + tip + ":");
- System.out.println(help.toString());
- if (scanner.hasNext()) {
- String ipt = scanner.next();
- if (StringUtils.isNotBlank(ipt)) {
- return ipt;
- }
- }
- throw new MybatisPlusException("请输入正确的" + tip + "!");
- }
-
- public static void main(String[] args) {
- // 代码生成器
- AutoGenerator mpg = new AutoGenerator();
-
- // 全局配置
- GlobalConfig gc = new GlobalConfig();
- String projectPath = System.getProperty("user.dir") + "/spbootpro";
- gc.setOutputDir(projectPath + "/src/main/java");
- gc.setAuthor("yangzong");
- gc.setOpen(false);
- gc.setBaseColumnList(true);
- gc.setBaseResultMap(true);
- // gc.setSwagger2(true); 实体属性 Swagger2 注解
- mpg.setGlobalConfig(gc);
-
- // 数据源配置
- DataSourceConfig dsc = new DataSourceConfig();
- dsc.setUrl("jdbc:mysql://localhost:3306/spbootpro?useUnicode=true&useSSL=false&characterEncoding=utf8");
- // dsc.setSchemaName("public");
- dsc.setDriverName("com.mysql.jdbc.Driver");
- dsc.setUsername("root");
- dsc.setPassword("1234");
- mpg.setDataSource(dsc);
-
- // 包配置
- PackageConfig pc = new PackageConfig();
- //pc.setModuleName(scanner("模块名"));
- pc.setParent("com.ycx.spbootpro");
- //设置包名
- pc.setEntity("model");
- mpg.setPackageInfo(pc);
-
- // 自定义配置
- InjectionConfig cfg = new InjectionConfig() {
- @Override
- public void initMap() {
- // to do nothing
- }
- };
-
- // 如果模板引擎是 freemarker
- String templatePath = "/templates/mybatis-generator/mapper2.xml.ftl";
- // 如果模板引擎是 velocity
- // String templatePath = "/templates/mapper.xml.vm";
-
- // 自定义输出配置
- List<FileOutConfig> focList = new ArrayList<>();
- // 自定义配置会被优先输出
- focList.add(new FileOutConfig(templatePath) {
- @Override
- public String outputFile(TableInfo tableInfo) {
- // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
- return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
- + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
- }
- });
- /*
- cfg.setFileCreate(new IFileCreate() {
- @Override
- public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
- // 判断自定义文件夹是否需要创建
- checkDir("调用默认方法创建的目录,自定义目录用");
- if (fileType == FileType.MAPPER) {
- // 已经生成 mapper 文件判断存在,不想重新生成返回 false
- return !new File(filePath).exists();
- }
- // 允许生成模板文件
- return true;
- }
- });
- */
- cfg.setFileOutConfigList(focList);
- mpg.setCfg(cfg);
-
- // 配置模板
- TemplateConfig templateConfig = new TemplateConfig();
-
- // 配置自定义输出模板
- //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
- templateConfig.setMapper("templates/mybatis-generator/mapper2.java");
- templateConfig.setEntity("templates/mybatis-generator/entity2.java");
- templateConfig.setService("templates/mybatis-generator/service2.java");
- templateConfig.setServiceImpl("templates/mybatis-generator/serviceImpl2.java");
- templateConfig.setController("templates/mybatis-generator/controller2.java");
- templateConfig.setXml(null);
- mpg.setTemplate(templateConfig);
-
- // 策略配置
- StrategyConfig strategy = new StrategyConfig();
- strategy.setNaming(NamingStrategy.underline_to_camel);
- strategy.setColumnNaming(NamingStrategy.underline_to_camel);
- //strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
- strategy.setEntityLombokModel(true);
- strategy.setRestControllerStyle(true);
- strategy.setEntitySerialVersionUID(false);
- // 公共父类
- //strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
- // 写于父类中的公共字段
- strategy.setSuperEntityColumns("id");
- strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
- strategy.setControllerMappingHyphenStyle(true);
- strategy.setTablePrefix("t_");
- mpg.setStrategy(strategy);
- mpg.setTemplateEngine(new FreemarkerTemplateEngine());
- mpg.execute();
- }
- }
CookieUtils :
- package com.ycx.spbootpro.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的值, 不编码
- * @param request
- * @param cookieName
- * @return
- */
- public static String getCookieValue(HttpServletRequest request, String cookieName) {
- return getCookieValue(request, cookieName, false);
- }
-
- /**
- *
- * @Description: 得到Cookie的值
- * @param request
- * @param cookieName
- * @param isDecoder
- * @return
- */
- 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的值
- * @param request
- * @param cookieName
- * @param encodeString
- * @return
- */
- 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的值 不设置生效时间默认浏览器关闭即失效,也不编码
- * @param request
- * @param response
- * @param cookieName
- * @param cookieValue
- */
- public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
- String cookieValue) {
- setCookie(request, response, cookieName, cookieValue, -1);
- }
-
- /**
- *
- * @Description: 设置Cookie的值 在指定时间内生效,但不编码
- * @param request
- * @param response
- * @param cookieName
- * @param cookieValue
- * @param cookieMaxage
- */
- 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信息
- * @param request
- * @param response
- * @param cookieName
- * @param cookieValue
- * @param isEncode
- */
- public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
- String cookieValue, boolean isEncode) {
- setCookie(request, response, cookieName, cookieValue, -1, isEncode);
- }
-
- /**
- *
- * @Description: 设置Cookie的值 在指定时间内生效, 编码参数
- * @param request
- * @param response
- * @param cookieName
- * @param cookieValue
- * @param cookieMaxage
- * @param isEncode
- */
- 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的值 在指定时间内生效, 编码参数(指定编码)
- * @param request
- * @param response
- * @param cookieName
- * @param cookieValue
- * @param cookieMaxage
- * @param encodeString
- */
- 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域名
- * @param request
- * @param response
- * @param cookieName
- */
- public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
- String cookieName) {
- doSetCookie(request, response, cookieName, null, -1, false);
- }
-
-
- /**
- *
- * @Description: 设置Cookie的值,并使其在指定时间内生效
- * @param request
- * @param response
- * @param cookieName
- * @param cookieValue
- * @param cookieMaxage cookie生效的最大秒数
- * @param isEncode
- */
- 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) {// 设置域名的cookie
- String 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的值,并使其在指定时间内生效
- * @param request
- * @param response
- * @param cookieName
- * @param cookieValue
- * @param cookieMaxage cookie生效的最大秒数
- * @param encodeString
- */
- private static final 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) {// 设置域名的cookie
- String 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的域名
- * @return
- */
- private static final 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.cn
- domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
- } else if (len <= 3 && len > 1) {
- // xxx.com or xxx.cn
- domainName = "." + 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){//判断是否是一个IP
- boolean 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;
- }
- }
DataUtils:
- package com.ycx.spbootpro.utils;
-
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- public class DataUtils
{ - /**
- * 转换方法,基于商品的排版情况(一行三列、一行四列等等)进行数据分行处理
- * @param cols 一行显示几列
- * @param goods 需要筛选的数据集
- * @return
- */
- public Map<String, List
> transfor(int cols, List goods ){ - Map<String,List
> data=new HashMap<>(); - List
rs=new ArrayList<>(); - int len=goods.size();
- for (int i = 0; i < len; i++) {
- rs.add(goods.get(i));
- if((i+1)%cols==0){
- data.put("goods"+(i+1),rs);
- if(i==len-1)
- break;
- rs=new ArrayList<>();
- continue;
- }
- if(i==len-1){
- data.put("goods"+(i+1),rs);
- }
- }
- return data;
- }
- }
JsonResponseBody:
- package com.ycx.spbootpro.utils;
-
- import lombok.Data;
-
- import java.io.Serializable;
-
- /**
- * 响应封装类
- */
- @Data
- public class JsonResponseBody
implements Serializable { -
- private String msg="OK";
- private T data;
- private Integer code;
- private Integer total;
-
- public JsonResponseBody(){
- this.data=null;
- this.code=JsonResponseStatus.SUCCESS.getCode();
- }
-
- public JsonResponseBody(T data){
- this.data=data;
- this.code=JsonResponseStatus.SUCCESS.getCode();
- }
-
- public JsonResponseBody(T data,Integer total){
- this.data=data;
- this.total=total;
- this.code=JsonResponseStatus.SUCCESS.getCode();
- }
-
- public JsonResponseBody(JsonResponseStatus jsonResponseStatus){
- this.msg=jsonResponseStatus.getMsg();
- this.code=jsonResponseStatus.getCode();
- }
-
- public JsonResponseBody(JsonResponseStatus jsonResponseStatus,T data){
- this.data=data;
- this.msg=jsonResponseStatus.getMsg();
- this.code=jsonResponseStatus.getCode();
- }
- }
JsonResponseStatus :
- package com.ycx.spbootpro.utils;
-
- import lombok.AllArgsConstructor;
- import lombok.Getter;
- import lombok.ToString;
-
- @Getter
- @ToString
- @AllArgsConstructor
- public enum JsonResponseStatus {
-
- SUCCESS(200,"OK"),
- ERROR(500,"内部错误"),
-
- USER_LOGIN_ERROR(100101,"用户名或者密码错误"),
- USER_MOBILE_ERROR(100102,"手机号码格式错误"),
- USER_PASSWORD_ERROR(100103,"用户密码错误"),
- USER_USERNAME_ERROR(100104,"账号不存在"),
-
- BIND_ERROR(200101,"参数校验异常"),
- TOKEN_EEROR(200102,"token令牌失效或已过期")
- ;
-
- private final Integer code;
- private final String msg;
- }
MD5Utils :
- package com.ycx.spbootpro.utils;
-
- import org.apache.commons.codec.digest.DigestUtils;
- import org.springframework.stereotype.Component;
-
- import java.util.UUID;
-
- /**
- * MD5加密
- * 用户端:password=MD5(明文+固定Salt)
- * 服务端:password=MD5(用户输入+随机Salt)
- * 用户端MD5加密是为了防止用户密码在网络中明文传输,服务端MD5加密是为了提高密码安全性,双重保险。
- */
- @Component
- public class MD5Utils {
-
- //加密盐,与前端一致
- private static String salt="f1g2h3j4";
-
- /**
- * md5加密
- * @param src
- * @return
- */
- public static String md5(String src){
- return DigestUtils.md5Hex(src);
- }
-
- /**
- * 获取加密的盐
- * @return
- */
- public static String createSalt(){
- return UUID.randomUUID().toString().replace("-","");
- }
-
- /**
- * 将前端的明文密码通过MD5加密方式加密成后端服务所需密码
- * 注意:该步骤实际是在前端完成!!!
- * @param inputPass 明文密码
- * @return
- */
- public static String inputPassToFormpass(String inputPass){
- //混淆固定盐salt,安全性更可靠
- String str=salt.charAt(1)+""+salt.charAt(5)+inputPass+salt.charAt(0)+""+salt.charAt(3);
- return md5(str);
- }
-
- /**
- * 将后端密文密码+随机salt生成数据库的密码
- * @param formPass
- * @param salt
- * @return
- */
- public static String formPassToDbPass(String formPass,String salt){
- //混淆固定盐salt,安全性更可靠
- String str=salt.charAt(7)+""+salt.charAt(9)+formPass+salt.charAt(1)+""+salt.charAt(5);
- return md5(str);
- }
-
- /**
- * 将用户输入的密码转换成数据库的密码
- * @param inputPass 明文密码
- * @param salt 盐
- * @return
- */
- public static String inputPassToDbPass(String inputPass,String salt){
- String formPass = inputPassToFormpass(inputPass);
- String dbPass = formPassToDbPass(formPass, salt);
- return dbPass;
- }
-
- public static void main(String[] args) {
- //d7aaa28e3b8e6c88352bd5e7c23829f9
- //5512a78a188b318c074a15f9b056a712
- String formPass = inputPassToFormpass("123456");
- System.out.println("前端加密密码:"+formPass);
- String salt = createSalt();
- System.out.println("后端加密随机盐:"+salt);
- String dbPass = formPassToDbPass(formPass, salt);
- System.out.println("后端加密密码:"+dbPass);
- System.out.println("-------------------------------------------");
- String dbPass1 = inputPassToDbPass("123456", salt);
- System.out.println("最终加密密码:"+dbPass1);
- }
- }
MybatisPlusConfig :
- package com.ycx.spbootpro.utils;
-
- import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
- import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
- import org.mybatis.spring.annotation.MapperScan;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.transaction.annotation.EnableTransactionManagement;
-
- //Spring boot方式
- @EnableTransactionManagement
- @Configuration
- @MapperScan("com.zking.shoppingpro.service.*.mapper*")
- public class MybatisPlusConfig {
-
- @Bean
- public PaginationInterceptor paginationInterceptor() {
- PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
- // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
- // paginationInterceptor.setOverflow(false);
- // 设置最大单页限制数量,默认 500 条,-1 不受限制
- // paginationInterceptor.setLimit(500);
- // 开启 count 的 join 优化,只针对部分 left join
- paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
- return paginationInterceptor;
- }
- }
PageBean :
- package com.ycx.spbootpro.utils;
-
- import javax.servlet.http.HttpServletRequest;
- import java.io.Serializable;
- import java.util.Map;
-
- public class PageBean implements Serializable {
-
- //页码
- private int page=1;
- //每页显示条数
- private int rows=10;
- //总记录数
- private int total=0;
- //是否分页标记
- private boolean pagination=true;
- //上一次请求的路径
- private String url;
- //请求参数Map集合
- private Map<String,String[]> map;
-
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- public Map<String, String[]> getMap() {
- return map;
- }
- public void setMap(Map<String, String[]> map) {
- this.map = map;
- }
- public int getPage() {
- return page;
- }
- public void setPage(int page) {
- this.page = page;
- }
- public int getRows() {
- return rows;
- }
- public void setRows(int rows) {
- this.rows = rows;
- }
- public int getTotal() {
- return total;
- }
- public void setTotal(int total) {
- this.total = total;
- }
- public boolean isPagination() {
- return pagination;
- }
- public void setPagination(boolean pagination) {
- this.pagination = pagination;
- }
-
- //重载setPage/setRows/setPagination方法
- public void setPage(String page) {
- if(null!=page&&!"".equals(page))
- this.page=Integer.parseInt(page);
- }
- public void setRows(String rows) {
- if(null!=rows&&!"".equals(rows))
- this.rows=Integer.parseInt(rows);
- }
- public void setPagination(String pagination) {
- if(null!=pagination&&!"".equals(pagination))
- this.pagination=Boolean.parseBoolean(pagination);
- }
-
- public void setRequest(HttpServletRequest req) {
- //获取前端提交的page/rows/pagination参数
- String page=req.getParameter("page");
- String rows=req.getParameter("rows");
- String pagination=req.getParameter("pagination");
-
- //设置属性
- this.setPage(page);
- this.setPagination(pagination);
- this.setRows(rows);
-
- //设置上一次请求的路径
- //第一次请求:
- //http://localhost:8080/项目名/请求路径.action?page=1
- //第二次请求:下一页 page=2
- //项目名+请求路径.action
- //req.getContextPath()+req.getServletPath()==req.getRequestURI()
- this.url=req.getRequestURI();
-
- //获取请求参数集合
- // checkbox name='hobby'
- // Map
hobby==key value==new String[]{"篮球","足球",..} - this.map=req.getParameterMap();
- }
-
- /**
- * 获取分页的起始位置
- * @return
- */
- public int getStartIndex() {
- //第1页:(1-1)*10 ==0 limit 0,10
- //第2页:(2-1)*10 ==10 limit 10,10
- //..
- return (this.page-1)*this.rows;
- }
-
- //获取末页、上一页、下一页
- /**
- * 获取末页
- * @return
- */
- public int getMaxPager() {
- int maxPager=this.total/this.rows;
- if(this.total%this.rows!=0)
- maxPager++;
- return maxPager;
- }
-
- /**
- * 获取上一页
- * @return
- */
- public int getPreviousPager() {
- int previousPager=this.page-1;
- if(previousPager<=1)
- previousPager=1;
- return previousPager;
- }
-
- /**
- * 获取下一页
- * @return
- */
- public int getNextPager() {
- int nextPager=this.page+1;
- if(nextPager>getMaxPager())
- nextPager=getMaxPager();
- return nextPager;
- }
- @Override
- public String toString() {
- return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination
- + ", url=" + url + ", map=" + map + "]";
- }
-
- }
-
ValidatorUtils :
- package com.ycx.spbootpro.utils;
-
- import org.apache.commons.lang3.StringUtils;
-
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
-
- /**
- * 正则校验工具类
- * @author 刘开宇
- */
- public class ValidatorUtils {
-
- private static final Pattern mobile_pattern=Pattern.compile("[1]([0-9])[0-9]{9}$");
-
- public static boolean isMobile(String mobile){
- if(StringUtils.isEmpty(mobile))
- return false;
- Matcher matcher = mobile_pattern.matcher(mobile);
- return matcher.matches();
- }
- }

在控制台输入表名:

生成成功:

- package com.ycx.spbootpro.controller;
-
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestMapping;
-
- /**
- * @author 杨总
- * @create 2022-11-05 17:20
- */
- @Controller
- public class PageController {
- /**
- * 直接跳转页面(没有层级文件夹的情况)
- * 列如:
- * http://localhost:8081/page/paint.html
- * http://localhost:8081/page/perfume.html
- *
- * @return
- */
- @RequestMapping("/page/{page}")
- public String page(@PathVariable(value = "page") String page) {
- return page;
- }
-
- /**
- * 直接跳转页面(存在层级文件夹的情况)
- *
- * @return
- */
- @RequestMapping("/page/{dir}/{page}")
- public String dir(@PathVariable(value = "dir") String dir,
- @PathVariable(value = "page") String page) {
- return dir + "/" + page;
- }
- }
- package com.ycx.spbootpro.generator;
-
- import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
- import com.baomidou.mybatisplus.core.toolkit.StringPool;
- import com.baomidou.mybatisplus.core.toolkit.StringUtils;
- import com.baomidou.mybatisplus.generator.AutoGenerator;
- import com.baomidou.mybatisplus.generator.InjectionConfig;
- import com.baomidou.mybatisplus.generator.config.*;
- import com.baomidou.mybatisplus.generator.config.po.TableInfo;
- import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
- import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Scanner;
-
- public class CodeGenerator {
-
- /**
- *
- * 读取控制台内容
- *
- */
- public static String scanner(String tip) {
- Scanner scanner = new Scanner(System.in);
- StringBuilder help = new StringBuilder();
- help.append("请输入" + tip + ":");
- System.out.println(help.toString());
- if (scanner.hasNext()) {
- String ipt = scanner.next();
- if (StringUtils.isNotBlank(ipt)) {
- return ipt;
- }
- }
- throw new MybatisPlusException("请输入正确的" + tip + "!");
- }
-
- public static void main(String[] args) {
- // 代码生成器
- AutoGenerator mpg = new AutoGenerator();
-
- // 全局配置
- GlobalConfig gc = new GlobalConfig();
- String projectPath = System.getProperty("user.dir") + "/spbootpro";
- gc.setOutputDir(projectPath + "/src/main/java");
- gc.setAuthor("yangzong");
- gc.setOpen(false);
- gc.setBaseColumnList(true);
- gc.setBaseResultMap(true);
- // gc.setSwagger2(true); 实体属性 Swagger2 注解
- mpg.setGlobalConfig(gc);
-
- // 数据源配置
- DataSourceConfig dsc = new DataSourceConfig();
- dsc.setUrl("jdbc:mysql://localhost:3306/spbootpro?useUnicode=true&useSSL=false&characterEncoding=utf8");
- // dsc.setSchemaName("public");
- dsc.setDriverName("com.mysql.jdbc.Driver");
- dsc.setUsername("root");
- dsc.setPassword("1234");
- mpg.setDataSource(dsc);
-
- // 包配置
- PackageConfig pc = new PackageConfig();
- //pc.setModuleName(scanner("模块名"));
- pc.setParent("com.ycx.spbootpro");
- //设置包名
- pc.setEntity("model");
- mpg.setPackageInfo(pc);
-
- // 自定义配置
- InjectionConfig cfg = new InjectionConfig() {
- @Override
- public void initMap() {
- // to do nothing
- }
- };
-
- // 如果模板引擎是 freemarker
- String templatePath = "/templates/mybatis-generator/mapper2.xml.ftl";
- // 如果模板引擎是 velocity
- // String templatePath = "/templates/mapper.xml.vm";
-
- // 自定义输出配置
- List<FileOutConfig> focList = new ArrayList<>();
- // 自定义配置会被优先输出
- focList.add(new FileOutConfig(templatePath) {
- @Override
- public String outputFile(TableInfo tableInfo) {
- // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
- return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
- + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
- }
- });
- /*
- cfg.setFileCreate(new IFileCreate() {
- @Override
- public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
- // 判断自定义文件夹是否需要创建
- checkDir("调用默认方法创建的目录,自定义目录用");
- if (fileType == FileType.MAPPER) {
- // 已经生成 mapper 文件判断存在,不想重新生成返回 false
- return !new File(filePath).exists();
- }
- // 允许生成模板文件
- return true;
- }
- });
- */
- cfg.setFileOutConfigList(focList);
- mpg.setCfg(cfg);
-
- // 配置模板
- TemplateConfig templateConfig = new TemplateConfig();
-
- // 配置自定义输出模板
- //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
- templateConfig.setMapper("templates/mybatis-generator/mapper2.java");
- templateConfig.setEntity("templates/mybatis-generator/entity2.java");
- templateConfig.setService("templates/mybatis-generator/service2.java");
- templateConfig.setServiceImpl("templates/mybatis-generator/serviceImpl2.java");
- templateConfig.setController("templates/mybatis-generator/controller2.java");
- templateConfig.setXml(null);
- mpg.setTemplate(templateConfig);
-
- // 策略配置
- StrategyConfig strategy = new StrategyConfig();
- strategy.setNaming(NamingStrategy.underline_to_camel);
- strategy.setColumnNaming(NamingStrategy.underline_to_camel);
- //strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
- strategy.setEntityLombokModel(true);
- strategy.setRestControllerStyle(true);
- strategy.setEntitySerialVersionUID(false);
- // 公共父类
- //strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
- // 写于父类中的公共字段
- strategy.setSuperEntityColumns("id");
- strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
- strategy.setControllerMappingHyphenStyle(true);
- strategy.setTablePrefix("t_");
- mpg.setStrategy(strategy);
- mpg.setTemplateEngine(new FreemarkerTemplateEngine());
- mpg.execute();
- }
- }
- package com.ycx.spbootpro.controller;
-
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.ycx.spbootpro.model.Goods;
- import com.ycx.spbootpro.service.IGoodsService;
- import com.ycx.spbootpro.utils.DataUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
-
- import java.util.List;
- import java.util.Map;
-
- /**
- * @author 杨总
- * @create 2022-11-04 21:02
- */
- @Controller
- public class IndexController {
- @Autowired
- private IGoodsService goodsService;
-
-
- @RequestMapping("/")
- public String index(Model model){
- // 摆件花艺
- List<Goods> goods01 = goodsService.list(new QueryWrapper<Goods>()
- .eq("goods_type", "01")
- .last("limit 6"));
-
- // 壁挂北欧
- List<Goods> goods07 = goodsService.list(new QueryWrapper<Goods>()
- .eq("goods_type", "07")
- .last("limit 12"));
-
- // 为了方便首页数据显示,方便摆放
- DataUtils<Goods> dataUtils = new DataUtils<>();
- Map<String, List<Goods>> gt01 = dataUtils.transfor(3, goods01);
- Map<String, List<Goods>> gt07 = dataUtils.transfor(4, goods07);
- model.addAttribute("gt01",gt01);
- model.addAttribute("gt07",gt07);
- return "index.html";
- }
-
- }
首页数据绑定语法:
1) list集合判空
<#if goods07?? && goods07?size gt 0>2) 遍历map集合,获取所有的keys
<#list goods07?keys as key>3) 根据key获取对应value值goods01[key]
<#list goods07[key] as g>
index.html:
- html>
- <html>
- <head lang="en">
- <#include "common/head.html" />
- <link rel="stylesheet" type="text/css" href="css/public.css"/>
- <link rel="stylesheet" type="text/css" href="css/index.css" />
- head>
- <div>
-
- <#include "common/top.html" />
-
-
- <div class="block_home_slider">
- <div id="home_slider" class="flexslider">
- <ul class="slides">
- <li>
- <div class="slide">
- <img src="img/banner2.jpg"/>
- div>
- li>
- <li>
- <div class="slide">
- <img src="img/banner1.jpg"/>
- div>
- li>
- ul>
- div>
- div>
-
-
- <div class="thImg">
- <div class="clearfix">
- <a href="${ctx}/page/vase_proList.html"><img src="img/i1.jpg"/>a>
- <a href="${ctx}/page/proList.html"><img src="img/i2.jpg"/>a>
- <a href="#2"><img src="img/i3.jpg"/>a>
- div>
- div>
-
-
- <div class="news">
- <div class="wrapper">
- <h2><img src="img/ih1.jpg"/>h2>
- <div class="top clearfix">
- <a href="${ctx}/page/proDetail.html"><img src="img/n1.jpg"/><p>p>a>
- <a href="${ctx}/page/proDetail.html"><img src="img/n2.jpg"/><p>p>a>
- <a href="${ctx}/page/proDetail.html"><img src="img/n3.jpg"/><p>p>a>
- div>
- <div class="bott clearfix">
- <a href="${ctx}/page/proDetail.html"><img src="img/n4.jpg"/><p>p>a>
- <a href="${ctx}/page/proDetail.html"><img src="img/n5.jpg"/><p>p>a>
- <a href="${ctx}/page/proDetail.html"><img src="img/n6.jpg"/><p>p>a>
- div>
- <h2><img src="img/ih2.jpg"/>h2>
- <#if gt01?? && gt01?size gt 0>
-
- <#list gt01?keys as key>
- <div class="flower clearfix tran">
- <#list gt01[key] as g>
- <a href="proDetail.html" class="clearfix">
- <dl>
- <dt>
- <span class="abl">span>
- <img src="${g.goodsImg}"/>
- <span class="abr">span>
- dt>
- <dd>${g.goodsName}dd>
- <dd><span>¥ ${g.goodsPrice}span>dd>
- dl>
- a>
- #list>
- div>
- #list>
- #if>
-
-
- div>
- div>
-
-
- <a href="#" class="ad"><img src="img/ib1.jpg"/>a>
-
-
- <div class="people">
- <div class="wrapper">
- <h2><img src="img/ih3.jpg"/>h2>
- <#if gt07?? && gt07?size gt 0>
- <#list gt07?keys as key>
- <div class="pList clearfix tran">
- <#list gt07[key] as g>
- <a href="proDetail.html">
- <dl>
- <dt>
- <span class="abl">span>
- <img src="${g.goodsImg}"/>
- <span class="abr">span>
- dt>
- <dd>${g.goodsName}dd>
- <dd><span>¥ ${g.goodsPrice}span>dd>
- dl>
- a>
- #list>
- div>
- #list>
- #if>>
-
- div>
- div>
-
- <#include "common/footer.html"/>
-
- <script src="js/public.js" type="text/javascript" charset="utf-8">script>
- <script src="js/nav.js" type="text/javascript" charset="utf-8">script>
- <script src="js/jquery.flexslider-min.js" type="text/javascript" charset="utf-8">script>
- <script type="text/javascript">
- $(function() {
- $('#home_slider').flexslider({
- animation: 'slide',
- controlNav: true,
- directionNav: true,
- animationLoop: true,
- slideshow: true,
- slideshowSpeed:2000,
- useCSS: false
- });
-
- });
- script>
- body>
- html>
运行:



定义UserDto.java接受前台传递的参数:
- package com.ycx.spbootpro.model.dto;
-
- import com.ycx.spbootpro.validator.IsMobile;
- import lombok.Data;
-
- import javax.validation.constraints.NotBlank;
-
- @Data
- public class UserDto {
- @NotBlank(message = "手机号码不能为空!")
- @IsMobile
- private String mobile;
- @NotBlank(message = "密码不能为空!")
- private String password;
- }
处理浏览器端的请求 UserController.java
- package com.ycx.spbootpro.controller;
-
-
- import com.ycx.spbootpro.model.dto.UserDto;
- import com.ycx.spbootpro.service.IUserService;
- import com.ycx.spbootpro.utils.JsonResponseBody;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
-
- import org.springframework.web.bind.annotation.RestController;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.validation.Valid;
-
- /**
- *
- * 用户信息表 前端控制器
- *
- *
- * @author yangzong
- * @since 2022-11-05
- */
- @RestController
- @RequestMapping("/user")
- public class UserController {
-
- @Autowired
- private IUserService userService;
-
- @RequestMapping("/toLogin")
- public JsonResponseBody toLogin(@Valid UserDto userDto,
- HttpServletRequest req,
- HttpServletResponse resp){
-
- return userService.toLogin(userDto,req,resp);
- }
- }
1.5.1)判断mobile和password是否为空
1.5.2)判断mobile格式是否正确
1.5.3)根据用户手机号码查询用户是否存在
1.5.4)校验账号
1.5.5)校验密码
- package com.ycx.spbootpro.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.ycx.spbootpro.exception.BusinessException;
- import com.ycx.spbootpro.model.User;
- import com.ycx.spbootpro.mapper.UserMapper;
- import com.ycx.spbootpro.model.dto.UserDto;
- import com.ycx.spbootpro.service.IUserService;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.ycx.spbootpro.utils.JsonResponseBody;
- import com.ycx.spbootpro.utils.JsonResponseStatus;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.validation.Valid;
-
- /**
- *
- * 用户信息表 服务实现类
- *
- *
- * @author yangzong
- * @since 2022-11-05
- */
- @Service
- public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
- @Autowired
- private UserMapper userMapper;
-
- @Override
- public JsonResponseBody toLogin(UserDto userDto, HttpServletRequest req, HttpServletResponse resp) {
- // 1.5.1)判断mobile和password是否为空(已由JSP303完成)
- // 1.5.2)判断mobile格式是否正确(自定义验证注解)
- // 1.5.3)根据用户手机号码查询用户是否存在
- User user = userMapper.selectOne(new QueryWrapper<User>()
- .eq("id", userDto.getMobile()));
-
- //1.5.4)校验账号
- //判断用户对象是否存在
- if(null==user)
- throw new BusinessException(JsonResponseStatus.USER_USERNAME_ERROR);
-
-
- // 1.5.5)校验密码
- if(!user.getPassword().equals(userDto.getPassword()))
- throw new BusinessException(JsonResponseStatus.USER_PASSWORD_ERROR);
-
- return new JsonResponseBody<>();
- }
-
- }
1.6.1)创建BusinessException
1.6.2)创建GlobalExceptionHandler
1.6.3)修改userLogin中的异常处理方式
1.7.1)创建自定义注解IsMobile
1.7.2)创建自定义校验规则类MobileValidator
1.7.3)在UserVo类的mobile属性中使用IsMobile注解
自定义JSR303注解,完成服务端登录账号的验证
查看用户表数据

- $(function () {
- alert(2);
-
- //登录向后台发送Ajax请求
- $("#login").click(function () {
- let mobile = $("#mobile").val();
- let password = $("#password").val();
-
-
- $.post("/user/toLogin",{
- mobile:mobile,
- password:password
- },function (res) {
- alert(res.msg)
- },"json");
- })
- });
1.手机号为空

2.手机号为非法字符

3.密码为空

4.手机号不存在

5.手机号密码正确

6.密码错误

前端加密:防止客户端浏览器F12导致密码泄露
后端加密:防止数据库数据泄露导致密码泄露
运行:

把 后端加密随机盐 和 加密密码 复制进表数据:

再次运行,每次运行出来的密码都不一样:


记得在login.html导入:

- package com.ycx.spbootpro.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.ycx.spbootpro.exception.BusinessException;
- import com.ycx.spbootpro.model.User;
- import com.ycx.spbootpro.mapper.UserMapper;
- import com.ycx.spbootpro.model.dto.UserDto;
- import com.ycx.spbootpro.service.IUserService;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.ycx.spbootpro.utils.JsonResponseBody;
- import com.ycx.spbootpro.utils.JsonResponseStatus;
- import com.ycx.spbootpro.utils.MD5Utils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.validation.Valid;
-
- /**
- *
- * 用户信息表 服务实现类
- *
- *
- * @author yangzong
- * @since 2022-11-05
- */
- @Service
- public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
- @Autowired
- private UserMapper userMapper;
-
- @Override
- public JsonResponseBody toLogin(UserDto userDto, HttpServletRequest req, HttpServletResponse resp) {
- // 1.5.1)判断mobile和password是否为空(已由JSP303完成)
- // 1.5.2)判断mobile格式是否正确(自定义验证注解)
- // 1.5.3)根据用户手机号码查询用户是否存在
- User user = userMapper.selectOne(new QueryWrapper<User>()
- .eq("id", userDto.getMobile()));
-
- //1.5.4)校验账号
- //判断用户对象是否存在
- if(null==user)
- throw new BusinessException(JsonResponseStatus.USER_USERNAME_ERROR);
-
- // 前台传递到后台的密码要经过工具类md5加密一次才有可能跟数据库密码匹配上
- String pwd = MD5Utils.formPassToDbPass(userDto.getPassword(), user.getSalt());
-
- // 1.5.5)校验密码
- if(!pwd.equals(user.getPassword()))
- throw new BusinessException(JsonResponseStatus.USER_PASSWORD_ERROR);
-
- return new JsonResponseBody<>();
- }
-
- }
- $(function () {
- alert(2);
-
- //登录向后台发送Ajax请求
- $("#login").click(function () {
- let mobile = $("#mobile").val();
- let password = $("#password").val();
- //1.密码加密
- //1) 定义固定盐
- let salt='f1g2h3j4';
- //2) 固定盐混淆
- let temp=salt.charAt(1)+""+salt.charAt(5)+password+salt.charAt(0)+""+salt.charAt(3);
- //3) 使用MD5完成前端第一次加密
- let pwd=md5(temp);
-
- $.post("/user/toLogin",{
- mobile:mobile,
- password:pwd
- },function (res) {
- alert(res.msg)
- },"json");
- })
- });
再次运行:


将登录的用户数据分别保留在客户端以及服务端
UserServiceImpl.java变更如下
- package com.ycx.spbootpro.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.ycx.spbootpro.exception.BusinessException;
- import com.ycx.spbootpro.model.User;
- import com.ycx.spbootpro.mapper.UserMapper;
- import com.ycx.spbootpro.model.dto.UserDto;
- import com.ycx.spbootpro.service.IRedisService;
- import com.ycx.spbootpro.service.IUserService;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.ycx.spbootpro.utils.CookieUtils;
- import com.ycx.spbootpro.utils.JsonResponseBody;
- import com.ycx.spbootpro.utils.JsonResponseStatus;
- import com.ycx.spbootpro.utils.MD5Utils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.validation.Valid;
- import java.util.UUID;
-
- /**
- *
- * 用户信息表 服务实现类
- *
- *
- * @author yangzong
- * @since 2022-11-05
- */
- @Service
- public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
- @Autowired
- private UserMapper userMapper;
- @Autowired
- private IRedisService redisService;
-
- @Override
- public JsonResponseBody toLogin(UserDto userDto, HttpServletRequest req, HttpServletResponse resp) {
- // 1.5.1)判断mobile和password是否为空(已由JSP303完成)
- // 1.5.2)判断mobile格式是否正确(自定义验证注解)
- // 1.5.3)根据用户手机号码查询用户是否存在
- User user = userMapper.selectOne(new QueryWrapper<User>()
- .eq("id", userDto.getMobile()));
-
- //1.5.4)校验账号
- //判断用户对象是否存在
- if(null==user)
- throw new BusinessException(JsonResponseStatus.USER_USERNAME_ERROR);
-
- // 前台传递到后台的密码要经过工具类md5加密一次才有可能跟数据库密码匹配上
- String pwd = MD5Utils.formPassToDbPass(userDto.getPassword(), user.getSalt());
-
- // 1.5.5)校验密码
- if(!pwd.equals(user.getPassword()))
- throw new BusinessException(JsonResponseStatus.USER_PASSWORD_ERROR);
-
- //6.将登陆用户对象与token令牌进行绑定保存到cookie和redis
- //创建登陆令牌token
- String token= UUID.randomUUID().toString().replace("-","");
- //将token令牌保存到cookie中
- CookieUtils.setCookie(req,resp,"token",token,7200);
- //将登陆token令牌与用户对象user绑定到redis中
- redisService.setUserToRedis(token,user);
- //将用户登陆的昵称设置到cookie中
- CookieUtils.setCookie(req,resp,"nickname",user.getNickname());
-
-
- return new JsonResponseBody<>();
- }
-
- }
IRedisService.java:
- package com.ycx.spbootpro.service;
-
- import com.ycx.spbootpro.model.User;
-
- /**
- * @author 杨总
- * @create 2022-11-05 20:45
- */
- public interface IRedisService {
-
- void setUserToRedis(String token, User user) ;
-
- User getUserByToken(String token);
- }
RedisServiceImpl.java:
- package com.ycx.spbootpro.service.impl;
-
- import com.ycx.spbootpro.model.User;
- import com.ycx.spbootpro.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;
-
- /**
- * @author 杨总
- * @create 2022-11-05 20:49
- */
- @Service
- public class RedisServiceImpl implements IRedisService {
- @Autowired
- private RedisTemplate<String,Object> redisTemplate;
-
- @Override
- public void setUserToRedis(String token, User user) {
- redisTemplate.opsForValue().set("user:"+token,user,7200L, TimeUnit.SECONDS);
- }
-
- @Override
- public User getUserByToken(String token) {
- return (User) redisTemplate.opsForValue().get("user:"+token);
- }
-
-
- }
测试如下:

今日内容就到这里啦~再会!