• springboot项目:前后端搭建


    目录

    一、springboot项目简介

    二、构建springboot项目

    创建SpringBoot项目并配置POM

    pom.xml

    application.yml

    启动类的配置

    SpbootproApplication 

    测试一下是否能访问前端

    IndexController 

    ​三、首页功能

     导入mybatisplus的代码生成器

    首页方法改造

     IndexController 

    页面数据展示

    index.html

    将页面的展示格式改变

    index.html

    四、用户明文登录 

    PageController

    UserDto 

    IUserService 

     UserServiceImpl 

    五、前端及数据库密码加密

    login.js

     UserServiceImpl 

    login.html

    六、服务端客户端登录密码管理

    UserServiceImpl 

    IRedisService

     IRedisServiceImpl 

     用的工具类

    CookieUtils 

     DataUtils 

     JsonResponseBody

     JsonResponseStatus

     MD5Utils 

     MybatisPlusConfig 

     PageBean 

     ValidatorUtils 

    一、springboot项目简介

    项目前期准备

    使用技术

    前端:Freemarker、jQuery
    后端:SpringBoot、MyBatisPlus、Lombok
    中间件:Redis

    数据表介绍

    用户表:t_user

    商品表:t_goods

    订单表:t_order

    订单项表:t_order_item

    数据源表:t_dict_type

    数据项表:t_dict_dat

     后期开发项目肯定是还要修改的 现在浅看一下

    二、构建springboot项目

    创建SpringBoot项目并配置POM

    构建项目时并没有选择任何组件(避免于所准备的依赖因为版本的问题导致出现问题)

    spring-boot-starter-freemarker
    spring-boot-starter-web
    mysql-connector-java 5.1.44
    lombok

    mybatis-plus-boot-starter 3.4.0
    mybatis-plus-generator 3.4.0

    HikariCP

    commons-codec
    commons-lang3 3.6

    spring-boot-starter-validation

    spring-boot-starter-data-redis

    参考

    pom.xml

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <parent>
    6. <groupId>org.springframework.bootgroupId>
    7. <artifactId>spring-boot-starter-parentartifactId>
    8. <version>2.3.9.RELEASEversion>
    9. <relativePath/>
    10. parent>
    11. <groupId>com.cdlgroupId>
    12. <artifactId>spbootproartifactId>
    13. <version>0.0.1-SNAPSHOTversion>
    14. <name>spbootproname>
    15. <description>Demo project for Spring Bootdescription>
    16. <properties>
    17. <java.version>1.8java.version>
    18. properties>
    19. <dependencies>
    20. <dependency>
    21. <groupId>org.springframework.bootgroupId>
    22. <artifactId>spring-boot-starter-freemarkerartifactId>
    23. dependency>
    24. <dependency>
    25. <groupId>org.springframework.bootgroupId>
    26. <artifactId>spring-boot-starter-webartifactId>
    27. dependency>
    28. <dependency>
    29. <groupId>mysqlgroupId>
    30. <artifactId>mysql-connector-javaartifactId>
    31. <scope>runtimescope>
    32. <version>5.1.44version>
    33. dependency>
    34. <dependency>
    35. <groupId>org.projectlombokgroupId>
    36. <artifactId>lombokartifactId>
    37. <optional>trueoptional>
    38. dependency>
    39. <dependency>
    40. <groupId>org.springframework.bootgroupId>
    41. <artifactId>spring-boot-starter-testartifactId>
    42. <scope>testscope>
    43. <exclusions>
    44. <exclusion>
    45. <groupId>org.junit.vintagegroupId>
    46. <artifactId>junit-vintage-engineartifactId>
    47. exclusion>
    48. exclusions>
    49. dependency>
    50. <dependency>
    51. <groupId>junitgroupId>
    52. <artifactId>junitartifactId>
    53. <scope>testscope>
    54. dependency>
    55. <dependency>
    56. <groupId>com.baomidougroupId>
    57. <artifactId>mybatis-plus-boot-starterartifactId>
    58. <version>3.4.0version>
    59. dependency>
    60. <dependency>
    61. <groupId>com.baomidougroupId>
    62. <artifactId>mybatis-plus-generatorartifactId>
    63. <version>3.4.0version>
    64. dependency>
    65. <dependency>
    66. <groupId>com.zaxxergroupId>
    67. <artifactId>HikariCPartifactId>
    68. dependency>
    69. <dependency>
    70. <groupId>commons-codecgroupId>
    71. <artifactId>commons-codecartifactId>
    72. dependency>
    73. <dependency>
    74. <groupId>org.apache.commonsgroupId>
    75. <artifactId>commons-lang3artifactId>
    76. <version>3.6version>
    77. dependency>
    78. <dependency>
    79. <groupId>org.springframework.bootgroupId>
    80. <artifactId>spring-boot-starter-validationartifactId>
    81. dependency>
    82. <dependency>
    83. <groupId>org.springframework.bootgroupId>
    84. <artifactId>spring-boot-starter-data-redisartifactId>
    85. dependency>
    86. <dependency>
    87. <groupId>org.apache.commonsgroupId>
    88. <artifactId>commons-pool2artifactId>
    89. dependency>
    90. <dependency>
    91. <groupId>com.alipay.sdkgroupId>
    92. <artifactId>alipay-easysdkartifactId>
    93. <version>2.0.1version>
    94. dependency>
    95. dependencies>
    96. <build>
    97. <plugins>
    98. <plugin>
    99. <groupId>org.springframework.bootgroupId>
    100. <artifactId>spring-boot-maven-pluginartifactId>
    101. plugin>
    102. plugins>
    103. build>
    104. project>

    application.yml参考如下

    application.yml

    1. server:
    2. port: 8081
    3. servlet:
    4. context-path: /
    5. spring:
    6. datasource:
    7. url: jdbc:mysql://localhost:3306/spbootpro?useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&characterEncoding=UTF8
    8. driver-class-name: com.mysql.jdbc.Driver
    9. password: 123456
    10. username: root
    11. hikari:
    12. # 最小空闲连接数量
    13. minimum-idle: 5
    14. # 空闲连接存活最大时间,默认60000010分钟)
    15. idle-timeout: 180000
    16. # 连接池最大连接数,默认是10
    17. maximum-pool-size: 10
    18. # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
    19. auto-commit: true
    20. # 连接池名称
    21. pool-name: MyHikariCP
    22. # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认180000030分钟
    23. max-lifetime: 1800000
    24. # 数据库连接超时时间,默认30秒,即30000
    25. connection-timeout: 30000
    26. freemarker:
    27. #设置编码格式
    28. charset: UTF-8
    29. #后缀
    30. suffix:
    31. #文档类型
    32. content-type: text/html
    33. #模板前端
    34. template-loader-path: classpath:/templates/
    35. #启用模板
    36. enabled: true
    37. mvc:
    38. static-path-pattern: /static/**
    39. redis:
    40. #服务端IP
    41. host: 192.168.26.128
    42. #端口
    43. port: 6379
    44. #密码
    45. password: 123456
    46. #选择数据库
    47. database: 0
    48. #超时时间
    49. timeout: 10000ms
    50. #Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问
    51. #Lettuce线程安全,Jedis线程非安全
    52. lettuce:
    53. pool:
    54. #最大连接数,默认8
    55. max-active: 8
    56. #最大连接阻塞等待时间,默认-1
    57. max-wait: 10000ms
    58. #最大空闲连接,默认8
    59. max-idle: 200
    60. #最小空闲连接,默认0
    61. min-idle: 5
    62. #mybatis-plus配置
    63. mybatis-plus:
    64. #所对应的 XML 文件位置
    65. mapper-locations: classpath*:/mapper/*Mapper.xml
    66. #别名包扫描路径
    67. type-aliases-package: com.cdl.spbootpro.model
    68. configuration:
    69. #驼峰命名规则
    70. map-underscore-to-camel-case: true
    71. #日志配置
    72. logging:
    73. level:
    74. com.cdl.spbootpro.mapper: debug

    redis使用的连接的IP是虚拟机所分配的

    启动类的配置

    SpbootproApplication 

    1. package com.cdl.spbootpro;
    2. import org.mybatis.spring.annotation.MapperScan;
    3. import org.springframework.boot.SpringApplication;
    4. import org.springframework.boot.autoconfigure.SpringBootApplication;
    5. import org.springframework.transaction.annotation.EnableTransactionManagement;
    6. @MapperScan({"com.cdl.spbootpro.mapper"})//扫描接口
    7. @EnableTransactionManagement//开启事务
    8. @SpringBootApplication
    9. public class SpbootproApplication {
    10. public static void main(String[] args) {
    11. SpringApplication.run(SpbootproApplication.class, args);
    12. }
    13. }

    将准备的页面资料以及图片等复制放入resources下

    测试一下是否能访问前端

    新建一个controller的包

    IndexController 

    1. package com.cdl.spbootpro.controller;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.RequestMapping;
    4. import org.springframework.web.bind.annotation.RestController;
    5. /**
    6. * @author cdl
    7. * @site www.cdl.com
    8. * @create 2022-11-05 17:31
    9. */
    10. @Controller
    11. public class IndexController {
    12. @RequestMapping("/")
    13. public String index(){
    14. // 模板前端
    15. // /templates+index.html+""
    16. //前缀+逻辑视图名+后缀
    17. return "index.html";
    18. }
    19. }

    运行启动类 浏览器输入地址 可以访问到我们准备的资源页面中

    但是此时的数据全都是静态的资源 页面中写的一样的



    三、首页功能

    目标:将数据库中的数据展示在首页的页面上

    数据库数据将这些数据展示到对应的商品上

     导入mybatisplus的代码生成器

    CodeGenerator 

    1. package com.cdl.spbootpro.generator;
    2. import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
    3. import com.baomidou.mybatisplus.core.toolkit.StringPool;
    4. import com.baomidou.mybatisplus.core.toolkit.StringUtils;
    5. import com.baomidou.mybatisplus.generator.AutoGenerator;
    6. import com.baomidou.mybatisplus.generator.InjectionConfig;
    7. import com.baomidou.mybatisplus.generator.config.*;
    8. import com.baomidou.mybatisplus.generator.config.po.TableInfo;
    9. import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
    10. import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
    11. import java.util.ArrayList;
    12. import java.util.List;
    13. import java.util.Scanner;
    14. public class CodeGenerator {
    15. /**
    16. *

    17. * 读取控制台内容
    18. *

    19. */
    20. public static String scanner(String tip) {
    21. Scanner scanner = new Scanner(System.in);
    22. StringBuilder help = new StringBuilder();
    23. help.append("请输入" + tip + ":");
    24. System.out.println(help.toString());
    25. if (scanner.hasNext()) {
    26. String ipt = scanner.next();
    27. if (StringUtils.isNotBlank(ipt)) {
    28. return ipt;
    29. }
    30. }
    31. throw new MybatisPlusException("请输入正确的" + tip + "!");
    32. }
    33. public static void main(String[] args) {
    34. // 代码生成器
    35. AutoGenerator mpg = new AutoGenerator();
    36. // 全局配置
    37. GlobalConfig gc = new GlobalConfig();
    38. String projectPath = System.getProperty("user.dir") + "/spbootpro";
    39. gc.setOutputDir(projectPath + "/src/main/java");
    40. gc.setAuthor("cdl");
    41. gc.setOpen(false);
    42. gc.setBaseColumnList(true);
    43. gc.setBaseResultMap(true);
    44. // gc.setSwagger2(true); 实体属性 Swagger2 注解
    45. mpg.setGlobalConfig(gc);
    46. // 数据源配置
    47. DataSourceConfig dsc = new DataSourceConfig();
    48. dsc.setUrl("jdbc:mysql://localhost:3306/spbootpro?useUnicode=true&useSSL=false&characterEncoding=utf8");
    49. // dsc.setSchemaName("public");
    50. dsc.setDriverName("com.mysql.jdbc.Driver");
    51. dsc.setUsername("root");
    52. dsc.setPassword("123456");
    53. mpg.setDataSource(dsc);
    54. // 包配置
    55. PackageConfig pc = new PackageConfig();
    56. //pc.setModuleName(scanner("模块名"));
    57. pc.setParent("com.cdl.spbootpro");
    58. //设置包名
    59. pc.setEntity("model");
    60. mpg.setPackageInfo(pc);
    61. // 自定义配置
    62. InjectionConfig cfg = new InjectionConfig() {
    63. @Override
    64. public void initMap() {
    65. // to do nothing
    66. }
    67. };
    68. // 如果模板引擎是 freemarker
    69. String templatePath = "/templates/mybatis-generator/mapper2.xml.ftl";
    70. // 如果模板引擎是 velocity
    71. // String templatePath = "/templates/mapper.xml.vm";
    72. // 自定义输出配置
    73. List focList = new ArrayList<>();
    74. // 自定义配置会被优先输出
    75. focList.add(new FileOutConfig(templatePath) {
    76. @Override
    77. public String outputFile(TableInfo tableInfo) {
    78. // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
    79. return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
    80. + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
    81. }
    82. });
    83. /*
    84. cfg.setFileCreate(new IFileCreate() {
    85. @Override
    86. public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
    87. // 判断自定义文件夹是否需要创建
    88. checkDir("调用默认方法创建的目录,自定义目录用");
    89. if (fileType == FileType.MAPPER) {
    90. // 已经生成 mapper 文件判断存在,不想重新生成返回 false
    91. return !new File(filePath).exists();
    92. }
    93. // 允许生成模板文件
    94. return true;
    95. }
    96. });
    97. */
    98. cfg.setFileOutConfigList(focList);
    99. mpg.setCfg(cfg);
    100. // 配置模板
    101. TemplateConfig templateConfig = new TemplateConfig();
    102. // 配置自定义输出模板
    103. //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
    104. templateConfig.setMapper("templates/mybatis-generator/mapper2.java");
    105. templateConfig.setEntity("templates/mybatis-generator/entity2.java");
    106. templateConfig.setService("templates/mybatis-generator/service2.java");
    107. templateConfig.setServiceImpl("templates/mybatis-generator/serviceImpl2.java");
    108. templateConfig.setController("templates/mybatis-generator/controller2.java");
    109. templateConfig.setXml(null);
    110. mpg.setTemplate(templateConfig);
    111. // 策略配置
    112. StrategyConfig strategy = new StrategyConfig();
    113. strategy.setNaming(NamingStrategy.underline_to_camel);
    114. strategy.setColumnNaming(NamingStrategy.underline_to_camel);
    115. //strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
    116. strategy.setEntityLombokModel(true);
    117. strategy.setRestControllerStyle(true);
    118. strategy.setEntitySerialVersionUID(false);
    119. // 公共父类
    120. //strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
    121. // 写于父类中的公共字段
    122. strategy.setSuperEntityColumns("id");
    123. strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
    124. strategy.setControllerMappingHyphenStyle(true);
    125. strategy.setTablePrefix("t_");
    126. mpg.setStrategy(strategy);
    127. mpg.setTemplateEngine(new FreemarkerTemplateEngine());
    128. mpg.execute();
    129. }
    130. }

    将自定义的代码生成模板放到templates目录下,覆盖Mybatis-plus默认的代码生成模板

    名为mybatis-generator的文件夹,将该文件夹放入resources下的templates下

    controller2.java.ftl

    1. package ${package.Controller};
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. <#if restControllerStyle>
    4. import org.springframework.web.bind.annotation.RestController;
    5. <#else>
    6. import org.springframework.stereotype.Controller;
    7. <#if superControllerClassPackage??>
    8. import ${superControllerClassPackage};
    9. /**
    10. * <p>
    11. * ${table.comment!} 前端控制器
    12. * p>
    13. *
    14. * @author ${author}
    15. * @since ${date}
    16. */
    17. <#if restControllerStyle>
    18. @RestController
    19. <#else>
    20. @Controller
    21. @RequestMapping("<#if package.ModuleName?? && package.ModuleName != "">/${package.ModuleName}/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}")
    22. <#if kotlin>
    23. class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()
    24. <#else>
    25. <#if superControllerClass??>
    26. public class ${table.controllerName} extends ${superControllerClass} {
    27. <#else>
    28. public class ${table.controllerName} {
    29. }

    entity2.java.ftl

    1. package ${package.Entity};
    2. <#list table.importPackages as pkg>
    3. import ${pkg};
    4. <#if swagger2>
    5. import io.swagger.annotations.ApiModel;
    6. import io.swagger.annotations.ApiModelProperty;
    7. if>
    8. <#if entityLombokModel>
    9. import lombok.Data;
    10. import lombok.EqualsAndHashCode;
    11. <#if chainModel>
    12. import lombok.experimental.Accessors;
    13. if>
    14. if>
    15. /**
    16. *

    17. * ${table.comment!}
    18. *

    19. *
    20. * @author ${author}
    21. * @since ${date}
    22. */
    23. <#if entityLombokModel>
    24. @Data
    25. <#if superEntityClass??>
    26. @EqualsAndHashCode(callSuper = true)
    27. <#else>
    28. @EqualsAndHashCode(callSuper = false)
    29. if>
    30. <#if chainModel>
    31. @Accessors(chain = true)
    32. if>
    33. if>
    34. <#if table.convert>
    35. @TableName("${table.name}")
    36. if>
    37. <#if swagger2>
    38. @ApiModel(value="${entity}对象", description="${table.comment!}")
    39. if>
    40. <#if superEntityClass??>
    41. public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}>if> {
    42. <#elseif activeRecord>
    43. public class ${entity} extends Model<${entity}> {
    44. <#else>
    45. public class ${entity} implements Serializable {
    46. if>
    47. <#if entitySerialVersionUID>
    48. private static final long serialVersionUID = 1L;
    49. if>
    50. <#-- ---------- BEGIN 字段循环遍历 ---------->
    51. <#list table.fields as field>
    52. <#if field.keyFlag>
    53. <#assign keyPropertyName="${field.propertyName}"/>
    54. if>
    55. <#if field.comment!?length gt 0>
    56. <#if swagger2>
    57. @ApiModelProperty(value = "${field.comment}")
    58. <#else>
    59. /**
    60. * ${field.comment}
    61. */
    62. if>
    63. if>
    64. <#if field.keyFlag>
    65. <#-- 主键 -->
    66. <#if field.keyIdentityFlag>
    67. @TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
    68. <#elseif idType??>
    69. @TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
    70. <#elseif field.convert>
    71. @TableId("${field.annotationColumnName}")
    72. if>
    73. <#-- 普通字段 -->
    74. <#elseif field.fill??>
    75. <#-- ----- 存在字段填充设置 ----->
    76. <#if field.convert>
    77. @TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
    78. <#else>
    79. @TableField(fill = FieldFill.${field.fill})
    80. if>
    81. <#elseif field.convert>
    82. @TableField("${field.annotationColumnName}")
    83. if>
    84. <#-- 乐观锁注解 -->
    85. <#if (versionFieldName!"") == field.name>
    86. @Version
    87. if>
    88. <#-- 逻辑删除注解 -->
    89. <#if (logicDeleteFieldName!"") == field.name>
    90. @TableLogic
    91. if>
    92. private ${field.propertyType} ${field.propertyName};
    93. <#------------ END 字段循环遍历 ---------->
    94. <#if !entityLombokModel>
    95. <#list table.fields as field>
    96. <#if field.propertyType == "boolean">
    97. <#assign getprefix="is"/>
    98. <#else>
    99. <#assign getprefix="get"/>
    100. if>
    101. public ${field.propertyType} ${getprefix}${field.capitalName}() {
    102. return ${field.propertyName};
    103. }
    104. <#if chainModel>
    105. public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
    106. <#else>
    107. public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
    108. if>
    109. this.${field.propertyName} = ${field.propertyName};
    110. <#if chainModel>
    111. return this;
    112. if>
    113. }
    114. if>
    115. <#if entityColumnConstant>
    116. <#list table.fields as field>
    117. public static final String ${field.name?upper_case} = "${field.name}";
    118. if>
    119. <#if activeRecord>
    120. @Override
    121. protected Serializable pkVal() {
    122. <#if keyPropertyName??>
    123. return this.${keyPropertyName};
    124. <#else>
    125. return null;
    126. if>
    127. }
    128. if>
    129. <#if !entityLombokModel>
    130. @Override
    131. public String toString() {
    132. return "${entity}{" +
    133. <#list table.fields as field>
    134. <#if field_index==0>
    135. "${field.propertyName}=" + ${field.propertyName} +
    136. <#else>
    137. ", ${field.propertyName}=" + ${field.propertyName} +
    138. if>
    139. "}";
    140. }
    141. if>
    142. }

    mapper2.java.ftl

    1. package ${package.Mapper};
    2. import ${package.Entity}.${entity};
    3. import ${superMapperClassPackage};
    4. /**
    5. *

    6. * ${table.comment!} Mapper 接口
    7. *

    8. *
    9. * @author ${author}
    10. * @since ${date}
    11. */
    12. <#if kotlin>
    13. interface ${table.mapperName} : ${superMapperClass}<${entity}>
    14. <#else>
    15. public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
    16. }
    17. if>

    mapper2.xml.ftl

    1. "1.0" encoding="UTF-8"?>
    2. "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    3. "${package.Mapper}.${table.mapperName}">
    4. <#if enableCache>
    5. "org.mybatis.caches.ehcache.LoggingEhcache"/>
    6. if>
    7. <#if baseResultMap>
    8. "BaseResultMap" type="${package.Entity}.${entity}">
    9. <#list table.fields as field>
    10. <#if field.keyFlag><#--生成主键排在第一位-->
    11. "${field.name}" property="${field.propertyName}" />
    12. if>
    13. <#list table.commonFields as field><#--生成公共字段 -->
    14. "${field.name}" property="${field.propertyName}" />
    15. <#list table.fields as field>
    16. <#if !field.keyFlag><#--生成普通字段 -->
    17. "${field.name}" property="${field.propertyName}" />
    18. if>
    19. if>
    20. <#if baseColumnList>
    21. "Base_Column_List">
    22. <#list table.commonFields as field>
    23. ${field.columnName},
    24. ${table.fieldNames}
    25. if>

    service2.java.ftl

    1. package ${package.Service};
    2. import ${package.Entity}.${entity};
    3. import ${superServiceClassPackage};
    4. /**
    5. *

    6. * ${table.comment!} 服务类
    7. *

    8. *
    9. * @author ${author}
    10. * @since ${date}
    11. */
    12. <#if kotlin>
    13. interface ${table.serviceName} : ${superServiceClass}<${entity}>
    14. <#else>
    15. public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
    16. }
    17. if>

    serviceImpl2.java.ftl

    1. package ${package.ServiceImpl};
    2. import ${package.Entity}.${entity};
    3. import ${package.Mapper}.${table.mapperName};
    4. import ${package.Service}.${table.serviceName};
    5. import ${superServiceImplClassPackage};
    6. import org.springframework.stereotype.Service;
    7. /**
    8. *

    9. * ${table.comment!} 服务实现类
    10. *

    11. *
    12. * @author ${author}
    13. * @since ${date}
    14. */
    15. @Service
    16. <#if kotlin>
    17. open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
    18. }
    19. <#else>
    20. public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
    21. }
    22. if>

    运行代码生成类 输入要生成的表名

     生成成功

     编辑IndexController并定义商品查询请求处理方法

    主要查询出 装饰摆件 和 墙式壁挂两个类别的上坪在首页进行展示

    SELECT * FROM t_goods;
    SELECT * FROM t_goods where goods_type = '01';
    SELECT * FROM t_goods where goods_type = '07';

    SELECT * FROM t_dict_type;
    SELECT * FROM t_dict_data;

    首页数据绑定语法

    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>

    首页方法改造

    注意:

     IndexController 

    1. package com.cdl.spbootpro.controller;
    2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    3. import com.cdl.spbootpro.model.Goods;
    4. import com.cdl.spbootpro.service.IGoodsService;
    5. import com.cdl.spbootpro.utils.DataUtils;
    6. import org.springframework.beans.factory.annotation.Autowired;
    7. import org.springframework.stereotype.Controller;
    8. import org.springframework.ui.Model;
    9. import org.springframework.web.bind.annotation.RequestMapping;
    10. import org.springframework.web.bind.annotation.RestController;
    11. import java.util.List;
    12. import java.util.Map;
    13. /**
    14. * @author cdl
    15. * @site www.cdl.com
    16. * @create 2022-11-05 17:31
    17. */
    18. @Controller
    19. public class IndexController {
    20. @Autowired
    21. private IGoodsService goodsService;
    22. @RequestMapping("/")
    23. public String index(Model model){
    24. // 模板前端
    25. // /templates+index.html+""
    26. //前缀+逻辑视图名+后缀
    27. // 主要查询出 装饰摆件 和 墙式壁挂两个类别的上坪在首页进行展示
    28. List goods01 = goodsService.list(new QueryWrapper().eq("goods_type", "01").last("limit 6"));
    29. List goods07 = goodsService.list(new QueryWrapper().eq("goods_type", "07").last("limit 12"));
    30. // 将数据转换成容易在页面上进行展现的数据格式
    31. DataUtils dataUtils = new DataUtils<>();
    32. Map> gt01 = dataUtils.transfor(3, goods01);
    33. Map> gt07 = dataUtils.transfor(4, goods07);
    34. model.addAttribute("gt01",gt01);
    35. model.addAttribute("gt07",gt07);
    36. return "index.html";
    37. }
    38. }

    页面数据展示

    index.html

    1. html>
    2. <html>
    3. <head lang="en">
    4. <#include "common/head.html">
    5. <link rel="stylesheet" type="text/css" href="css/public.css"/>
    6. <link rel="stylesheet" type="text/css" href="css/index.css" />
    7. head>
    8. <body>
    9. <#include "common/top.html">
    10. <div class="block_home_slider">
    11. <div id="home_slider" class="flexslider">
    12. <ul class="slides">
    13. <li>
    14. <div class="slide">
    15. <img src="img/banner2.jpg"/>
    16. div>
    17. li>
    18. <li>
    19. <div class="slide">
    20. <img src="img/banner1.jpg"/>
    21. div>
    22. li>
    23. ul>
    24. div>
    25. div>
    26. <div class="thImg">
    27. <div class="clearfix">
    28. <a href="${ctx}/page/vase_proList.html"><img src="img/i1.jpg"/>a>
    29. <a href="${ctx}/page/proList.html"><img src="img/i2.jpg"/>a>
    30. <a href="#2"><img src="img/i3.jpg"/>a>
    31. div>
    32. div>
    33. <div class="news">
    34. <div class="wrapper">
    35. <h2><img src="img/ih1.jpg"/>h2>
    36. <div class="top clearfix">
    37. <a href="${ctx}/page/proDetail.html"><img src="img/n1.jpg"/><p>p>a>
    38. <a href="${ctx}/page/proDetail.html"><img src="img/n2.jpg"/><p>p>a>
    39. <a href="${ctx}/page/proDetail.html"><img src="img/n3.jpg"/><p>p>a>
    40. div>
    41. <div class="bott clearfix">
    42. <a href="${ctx}/page/proDetail.html"><img src="img/n4.jpg"/><p>p>a>
    43. <a href="${ctx}/page/proDetail.html"><img src="img/n5.jpg"/><p>p>a>
    44. <a href="${ctx}/page/proDetail.html"><img src="img/n6.jpg"/><p>p>a>
    45. div>
    46. <h2><img src="img/ih2.jpg"/>h2>
    47. <#if gt01?? && gt01?size gt 0>
    48. <#list gt01?keys as key>
    49. <div class="flower clearfix tran">
    50. <#list gt01[key] as g>
    51. <a href="proDetail.html" class="clearfix">
    52. <dl>
    53. <dt>
    54. <span class="abl">span>
    55. <img src="${g.goodsImg}"/>
    56. <span class="abr">span>
    57. dt>
    58. <dd>${g.goodsName}dd>
    59. <dd><span>¥ ${g.goodsPrice}span>dd>
    60. dl>
    61. a>
    62. div>
    63. div>
    64. div>
    65. <a href="#" class="ad"><img src="img/ib1.jpg"/>a>
    66. <div class="people">
    67. <div class="wrapper">
    68. <h2><img src="img/ih3.jpg"/>h2>
    69. <div class="pList clearfix tran">
    70. <a href="proDetail.html">
    71. <dl>
    72. <dt>
    73. <span class="abl">span>
    74. <img src="img/s7.jpg"/>
    75. <span class="abr">span>
    76. dt>
    77. <dd>【最家】不锈钢壁饰墙饰软装dd>
    78. <dd><span>¥688.00span>dd>
    79. dl>
    80. a>
    81. <a href="proDetail.html">
    82. <dl>
    83. <dt>
    84. <span class="abl">span>
    85. <img src="img/s10.jpg"/>
    86. <span class="abr">span>
    87. dt>
    88. <dd>【最家】小城动物木板画壁挂北欧dd>
    89. <dd><span>¥188.00span>dd>
    90. dl>
    91. a>
    92. <a href="proDetail.html">
    93. <dl>
    94. <dt>
    95. <span class="abl">span>
    96. <img src="img/s4.jpg"/>
    97. <span class="abr">span>
    98. dt>
    99. <dd>【最家】玄关假山水壁饰背景墙饰挂件创意dd>
    100. <dd><span>¥599.00span>dd>
    101. dl>
    102. a>
    103. <a href="proDetail.html">
    104. <dl>
    105. <dt>
    106. <span class="abl">span>
    107. <img src="img/s9.jpg"/>
    108. <span class="abr">span>
    109. dt>
    110. <dd>【最家】金属树枝壁饰铜鸟装饰品dd>
    111. <dd><span>¥928.00span>dd>
    112. dl>
    113. a>
    114. div>
    115. <div class="pList clearfix tran">
    116. <a href="proDetail.html">
    117. <dl>
    118. <dt>
    119. <span class="abl">span>
    120. <img src="img/s6.jpg"/>
    121. <span class="abr">span>
    122. dt>
    123. <dd>【最家】金属壁饰创意背景墙面挂件创意dd>
    124. <dd><span>¥228.00span>dd>
    125. dl>
    126. a>
    127. <a href="proDetail.html">
    128. <dl>
    129. <dt>
    130. <span class="abl">span>
    131. <img src="img/s8.jpg"/>
    132. <span class="abr">span>
    133. dt>
    134. <dd>【最家】小城动物木板画壁挂北欧dd>
    135. <dd><span>¥199.00span>dd>
    136. dl>
    137. a>
    138. <a href="proDetail.html">
    139. <dl>
    140. <dt>
    141. <span class="abl">span>
    142. <img src="img/s12.jpg"/>
    143. <span class="abr">span>
    144. dt>
    145. <dd>【最家】欧式复古挂钟创意餐厅钟表家居挂件dd>
    146. <dd><span>¥666.00span>dd>
    147. dl>
    148. a>
    149. <a href="proDetail.html">
    150. <dl>
    151. <dt>
    152. <span class="abl">span>
    153. <img src="img/s1.jpg"/>
    154. <span class="abr">span>
    155. dt>
    156. <dd>【最家】客厅地中海欧式现代相片墙创意dd>
    157. <dd><span>¥59.80span>dd>
    158. dl>
    159. a>
    160. div>
    161. <div class="pList clearfix tran">
    162. <a href="proDetail.html">
    163. <dl>
    164. <dt>
    165. <span class="abl">span>
    166. <img src="img/s5.jpg"/>
    167. <span class="abr">span>
    168. dt>
    169. <dd>【最家】铁艺荷叶壁挂软装背景墙上装饰品dd>
    170. <dd><span>¥800.00span>dd>
    171. dl>
    172. a>
    173. <a href="proDetail.html">
    174. <dl>
    175. <dt>
    176. <span class="abl">span>
    177. <img src="img/s3.jpg"/>
    178. <span class="abr">span>
    179. dt>
    180. <dd>【最家】欧式照片墙 创意组合结婚礼物dd>
    181. <dd><span>¥189.00span>dd>
    182. dl>
    183. a>
    184. <a href="proDetail.html">
    185. <dl>
    186. <dt>
    187. <span class="abl">span>
    188. <img src="img/s2.jpg"/>
    189. <span class="abr">span>
    190. dt>
    191. <dd>【最家】欧式钟表相框墙挂墙创意组合dd>
    192. <dd><span>¥148.00span>dd>
    193. dl>
    194. a>
    195. <a href="proDetail.html">
    196. <dl>
    197. <dt>
    198. <span class="abl">span>
    199. <img src="img/s11.jpg"/>
    200. <span class="abr">span>
    201. dt>
    202. <dd>【最家】小城动物木板画壁挂北欧dd>
    203. <dd><span>¥188.00span>dd>
    204. dl>
    205. a>
    206. div>
    207. div>
    208. div>
    209. <#include "common/footer.html"/>
    210. <script src="js/public.js" type="text/javascript" charset="utf-8">script>
    211. <script src="js/nav.js" type="text/javascript" charset="utf-8">script>
    212. <script src="js/jquery.flexslider-min.js" type="text/javascript" charset="utf-8">script>
    213. <script type="text/javascript">
    214. $(function() {
    215. $('#home_slider').flexslider({
    216. animation: 'slide',
    217. controlNav: true,
    218. directionNav: true,
    219. animationLoop: true,
    220. slideshow: true,
    221. slideshowSpeed:2000,
    222. useCSS: false
    223. });
    224. });
    225. script>
    226. body>
    227. html>

    运行结果:

     可以发现所有的数据已经不一样了

    将页面的展示格式改变

    index.html

    1. html>
    2. <html>
    3. <head lang="en">
    4. <#include "common/head.html">
    5. <link rel="stylesheet" type="text/css" href="css/public.css"/>
    6. <link rel="stylesheet" type="text/css" href="css/index.css" />
    7. head>
    8. <body>
    9. <#include "common/top.html">
    10. <div class="block_home_slider">
    11. <div id="home_slider" class="flexslider">
    12. <ul class="slides">
    13. <li>
    14. <div class="slide">
    15. <img src="img/banner2.jpg"/>
    16. div>
    17. li>
    18. <li>
    19. <div class="slide">
    20. <img src="img/banner1.jpg"/>
    21. div>
    22. li>
    23. ul>
    24. div>
    25. div>
    26. <div class="thImg">
    27. <div class="clearfix">
    28. <a href="${ctx}/page/vase_proList.html"><img src="img/i1.jpg"/>a>
    29. <a href="${ctx}/page/proList.html"><img src="img/i2.jpg"/>a>
    30. <a href="#2"><img src="img/i3.jpg"/>a>
    31. div>
    32. div>
    33. <div class="news">
    34. <div class="wrapper">
    35. <h2><img src="img/ih1.jpg"/>h2>
    36. <div class="top clearfix">
    37. <a href="${ctx}/page/proDetail.html"><img src="img/n1.jpg"/><p>p>a>
    38. <a href="${ctx}/page/proDetail.html"><img src="img/n2.jpg"/><p>p>a>
    39. <a href="${ctx}/page/proDetail.html"><img src="img/n3.jpg"/><p>p>a>
    40. div>
    41. <div class="bott clearfix">
    42. <a href="${ctx}/page/proDetail.html"><img src="img/n4.jpg"/><p>p>a>
    43. <a href="${ctx}/page/proDetail.html"><img src="img/n5.jpg"/><p>p>a>
    44. <a href="${ctx}/page/proDetail.html"><img src="img/n6.jpg"/><p>p>a>
    45. div>
    46. <h2><img src="img/ih2.jpg"/>h2>
    47. <#if gt01?? && gt01?size gt 0>
    48. <#list gt01?keys as key>
    49. <div class="flower clearfix tran">
    50. <#list gt01[key] as g>
    51. <a href="proDetail.html" class="clearfix">
    52. <dl>
    53. <dt>
    54. <span class="abl">span>
    55. <img src="${g.goodsImg}"/>
    56. <span class="abr">span>
    57. dt>
    58. <dd>${g.goodsName}dd>
    59. <dd><span>¥ ${g.goodsPrice}span>dd>
    60. dl>
    61. a>
    62. div>
    63. div>
    64. div>
    65. <a href="#" class="ad"><img src="img/ib1.jpg"/>a>
    66. <div class="people">
    67. < class="wrapper">
    68. <h2><img src="img/ih3.jpg"/>h2>
    69. <#if gt07?? && gt07?size gt 0>
    70. <#list gt07?keys as key>
    71. <div class="pList clearfix tran">
    72. <#list gt07[key] as g>
    73. <a href="proDetail.html">
    74. <dl>
    75. <dt>
    76. <span class="abl">span>
    77. <img src="${g.goodsImg}"/>
    78. <span class="abr">span>
    79. dt>
    80. <dd>${g.goodsName}dd>
    81. <dd><span>¥ ${g.goodsPrice}span>dd>
    82. dl>
    83. a>
    84. div>
    85. div>
    86. div>
    87. <#include "common/footer.html"/>
    88. <script src="js/public.js" type="text/javascript" charset="utf-8">script>
    89. <script src="js/nav.js" type="text/javascript" charset="utf-8">script>
    90. <script src="js/jquery.flexslider-min.js" type="text/javascript" charset="utf-8">script>
    91. <script type="text/javascript">
    92. $(function() {
    93. $('#home_slider').flexslider({
    94. animation: 'slide',
    95. controlNav: true,
    96. directionNav: true,
    97. animationLoop: true,
    98. slideshow: true,
    99. slideshowSpeed:2000,
    100. useCSS: false
    101. });
    102. });
    103. script>
    104. body>
    105. html>

    此时的页面还是不能够跳转的

    四、用户明文登录 

    要实现登录功能,要确保页面间能够跳转

    公共跳转控制器PageController

    PageController

    1. package com.cdl.spbootpro.controller;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.PathVariable;
    4. import org.springframework.web.bind.annotation.RequestMapping;
    5. /**
    6. * @author cdl
    7. * @site www.cdl.com
    8. * @create 2022-11-05 21:45
    9. */
    10. @Controller
    11. public class PageController {
    12. /**
    13. * 直接跳转页面(没有层级文件夹的情况)
    14. * 列如:
    15. * http://localhost:8081/page/paint.html
    16. * http://localhost:8081/page/perfume.html
    17. *
    18. * @return
    19. */
    20. @RequestMapping("/page/{page}")
    21. public String page(@PathVariable(value = "page") String page) {
    22. return page;
    23. }
    24. /**
    25. * 直接跳转页面(存在层级文件夹的情况)
    26. *
    27. * @return
    28. */
    29. @RequestMapping("/page/{dir}/{page}")
    30. public String dir(@PathVariable(value = "dir") String dir, @PathVariable(value = "page") String page) {
    31. return dir + "/" + page;
    32. }
    33. }

    跳转成功

     在js下建一个包(login)再建一个文件(login.js)用于写登录的内容

    1. $(function () {
    2. // alert(1);
    3. // 给登录按钮添加事件
    4. $("#login").click(function () {
    5. let mobile = $("#mobile").val();
    6. let password = $("#password").val();
    7. //2.向后台发起登录ajax请求
    8. $.post('/user/userLogin',{
    9. mobile:mobile,
    10. password:password
    11. },function(rs){
    12. if(rs.code!=200){
    13. alert(rs.msg);
    14. }else
    15. //alert(rs.msg);
    16. location.href='/';
    17. },'json');
    18. });
    19. });

    定义UserDto.java接受前台传递的参数

    UserDto 

    1. package com.cdl.spbootpro.model.dto;
    2. import com.cdl.spbootpro.validator.IsMobile;
    3. import lombok.Data;
    4. import javax.validation.constraints.NotBlank;
    5. @Data
    6. public class UserDto {
    7. @NotBlank(message = "手机号码不能为空!")
    8. @IsMobile
    9. private String mobile;
    10. @NotBlank(message = "密码不能为空!")
    11. private String password;
    12. }

    处理浏览器端的请求 UserController

    1. package com.cdl.spbootpro.controller;
    2. import com.cdl.spbootpro.model.dto.UserDto;
    3. import com.cdl.spbootpro.service.IUserService;
    4. import com.cdl.spbootpro.utils.JsonResponseBody;
    5. import org.springframework.beans.factory.annotation.Autowired;
    6. import org.springframework.web.bind.annotation.RequestMapping;
    7. import org.springframework.web.bind.annotation.RestController;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import javax.validation.Valid;
    11. /**
    12. *

    13. * 用户信息表 前端控制器
    14. *

    15. *
    16. * @author cdl
    17. * @since 2022-11-05
    18. */
    19. @RestController
    20. @RequestMapping("/user")
    21. public class UserController {
    22. @Autowired
    23. private IUserService userService;
    24. @RequestMapping("/userLogin")
    25. public JsonResponseBody userLogin(@Valid UserDto userDto,
    26. HttpServletRequest req,
    27. HttpServletResponse resp){
    28. return userService.userLogin(userDto,req,resp);
    29. }
    30. }

    对应的业务代码

    IUserService 

    1. package com.cdl.spbootpro.service;
    2. import com.cdl.spbootpro.model.User;
    3. import com.baomidou.mybatisplus.extension.service.IService;
    4. import com.cdl.spbootpro.model.dto.UserDto;
    5. import com.cdl.spbootpro.utils.JsonResponseBody;
    6. import javax.servlet.http.HttpServletRequest;
    7. import javax.servlet.http.HttpServletResponse;
    8. /**
    9. *

    10. * 用户信息表 服务类
    11. *

    12. *
    13. * @author cdl
    14. * @since 2022-11-05
    15. */
    16. public interface IUserService extends IService {
    17. JsonResponseBody userLogin(UserDto userDto, HttpServletRequest req, HttpServletResponse resp);
    18. }

     UserServiceImpl 

    1. package com.cdl.spbootpro.service.impl;
    2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    3. import com.cdl.spbootpro.exception.BusinessException;
    4. import com.cdl.spbootpro.model.User;
    5. import com.cdl.spbootpro.mapper.UserMapper;
    6. import com.cdl.spbootpro.model.dto.UserDto;
    7. import com.cdl.spbootpro.service.IUserService;
    8. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    9. import com.cdl.spbootpro.utils.JsonResponseBody;
    10. import com.cdl.spbootpro.utils.JsonResponseStatus;
    11. import org.springframework.beans.factory.annotation.Autowired;
    12. import org.springframework.stereotype.Service;
    13. import javax.servlet.http.HttpServletRequest;
    14. import javax.servlet.http.HttpServletResponse;
    15. /**
    16. *

    17. * 用户信息表 服务实现类
    18. *

    19. *
    20. * @author cdl
    21. * @since 2022-11-05
    22. */
    23. @Service
    24. public class UserServiceImpl extends ServiceImpl implements IUserService {
    25. @Autowired
    26. private UserMapper userMapper;
    27. @Override
    28. public JsonResponseBody userLogin(UserDto userDto, HttpServletRequest req, HttpServletResponse resp) {
    29. //要做的事情:
    30. // 判断mobile和password是否为空 已由JSP303完成(在controller中的UserDto添加@Valid便可解决)
    31. //判断mobile格式是否正确 (自定义验证注解@IsMobile)
    32. //根据用户手机号码查询用户
    33. User user = userMapper.selectOne(new QueryWrapper()
    34. .eq("id", userDto.getMobile()));
    35. // 判断所查询的用户是否存在(校验账号)
    36. if(null==user)
    37. throw new BusinessException(JsonResponseStatus.USER_USERNAME_ERROR);
    38. //校验密码
    39. if(!user.getPassword().equals(userDto.getPassword()))
    40. throw new BusinessException(JsonResponseStatus.USER_PASSWORD_ERROR);
    41. return new JsonResponseBody<>();
    42. }
    43. }

    注意:

     此时的数据库(没有使用盐加密)

     测试一下

    什么也不填

    输入正确的手机号码和密码(123456)

    会进入主页面

     输入错的密码 

    五、前端及数据库密码加密

    盐加密

    前端加密:防止客户端浏览器F12导致密码泄露

    后端加密:防止数据库数据泄露导致密码泄露

    login.js变更如下

    login.js

    1. $(function () {
    2. // alert(1);
    3. // 给登录按钮添加事件
    4. $("#login").click(function () {
    5. let mobile = $("#mobile").val();
    6. let password = $("#password").val();
    7. //1.密码加密
    8. //1) 定义固定盐
    9. let salt='f1g2h3j4';
    10. //2) 固定盐混淆
    11. let temp=salt.charAt(1)+""+salt.charAt(5)+password+salt.charAt(0)+""+salt.charAt(3);
    12. //3) 使用MD5完成前端第一次加密
    13. let pwd=md5(temp);
    14. console.log("mobile=%s,password=%s",mobile,pwd);
    15. //2.向后台发起登录ajax请求
    16. $.post('/user/userLogin',{
    17. mobile:mobile,
    18. password:pwd
    19. },function(rs){
    20. if(rs.code!=200){
    21. alert(rs.msg);
    22. }else
    23. //alert(rs.msg);
    24. location.href='/';
    25. },'json');
    26. });
    27. });

     UserServiceImpl 

    1. package com.cdl.spbootpro.service.impl;
    2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    3. import com.cdl.spbootpro.exception.BusinessException;
    4. import com.cdl.spbootpro.model.User;
    5. import com.cdl.spbootpro.mapper.UserMapper;
    6. import com.cdl.spbootpro.model.dto.UserDto;
    7. import com.cdl.spbootpro.service.IUserService;
    8. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    9. import com.cdl.spbootpro.utils.JsonResponseBody;
    10. import com.cdl.spbootpro.utils.JsonResponseStatus;
    11. import com.cdl.spbootpro.utils.MD5Utils;
    12. import org.springframework.beans.factory.annotation.Autowired;
    13. import org.springframework.stereotype.Service;
    14. import javax.servlet.http.HttpServletRequest;
    15. import javax.servlet.http.HttpServletResponse;
    16. /**
    17. *

    18. * 用户信息表 服务实现类
    19. *

    20. *
    21. * @author cdl
    22. * @since 2022-11-05
    23. */
    24. @Service
    25. public class UserServiceImpl extends ServiceImpl implements IUserService {
    26. @Autowired
    27. private UserMapper userMapper;
    28. @Override
    29. public JsonResponseBody userLogin(UserDto userDto, HttpServletRequest req, HttpServletResponse resp) {
    30. //要做的事情:
    31. // 判断mobile和password是否为空 已由JSP303完成(在controller中的UserDto添加@Valid便可解决)
    32. //判断mobile格式是否正确 (自定义验证注解@IsMobile)
    33. //根据用户手机号码查询用户
    34. User user = userMapper.selectOne(new QueryWrapper()
    35. .eq("id", userDto.getMobile()));
    36. // 判断所查询的用户是否存在(校验账号)
    37. if(null==user)
    38. throw new BusinessException(JsonResponseStatus.USER_USERNAME_ERROR);
    39. //前台传递到后台的密码 要经过工具类MD5加密一次才有可能跟数据库密码匹配上
    40. String pwd = MD5Utils.formPassToDbPass(userDto.getPassword(), user.getSalt());
    41. //校验密码
    42. if(!user.getPassword().equals(pwd))
    43. throw new BusinessException(JsonResponseStatus.USER_PASSWORD_ERROR);
    44. return new JsonResponseBody<>();
    45. }
    46. }

    在login.html中引入md5.js

    login.html

    1. html>
    2. <html>
    3. <head>
    4. <#include "common/head.html">
    5. <link rel="stylesheet" type="text/css" href="css/public.css"/>
    6. <link rel="stylesheet" type="text/css" href="css/login.css"/>
    7. <script type="text/javascript" src="js/jquery-1.12.4.min.js">script>
    8. <script type="text/javascript" src="js/md5.js">script>
    9. <script type="text/javascript" src="js/login/login.js">script>
    10. head>
    11. <body>
    12. <div class="login">
    13. <form action="#" method="post">
    14. <h1><a href="${ctx}/"><img src="img/temp/logo.png">a>h1>
    15. <p>p>
    16. <div class="msg-warn hide"><b>b>公共场所不建议自动登录,以防账号丢失div>
    17. <p><input style="font-size:14px;" type="text" id="mobile" value="" placeholder="邮箱/手机号">p>
    18. <p><input style="font-size:14px;" type="password" id="password" value="" placeholder="密码">p>
    19. <p><input type="button" id="login" value="登 录">p>
    20. <p class="txt"><a class="" href="${ctx}/page/reg.html">免费注册a><a href="${ctx}/page/forget.html">忘记密码?a>p>
    21. form>
    22. div>
    23. body>
    24. html>

    加密成功

    六、服务端客户端登录密码管理

    登录令牌管理

    将登录的用户数据分别保留在客户端以及服务端

     UserServiceImpl.java变更如下

    UserServiceImpl 

    1. package com.cdl.spbootpro.service.impl;
    2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    3. import com.cdl.spbootpro.exception.BusinessException;
    4. import com.cdl.spbootpro.model.User;
    5. import com.cdl.spbootpro.mapper.UserMapper;
    6. import com.cdl.spbootpro.model.dto.UserDto;
    7. import com.cdl.spbootpro.service.IRedisService;
    8. import com.cdl.spbootpro.service.IUserService;
    9. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    10. import com.cdl.spbootpro.utils.CookieUtils;
    11. import com.cdl.spbootpro.utils.JsonResponseBody;
    12. import com.cdl.spbootpro.utils.JsonResponseStatus;
    13. import com.cdl.spbootpro.utils.MD5Utils;
    14. import org.springframework.beans.factory.annotation.Autowired;
    15. import org.springframework.stereotype.Service;
    16. import javax.servlet.http.HttpServletRequest;
    17. import javax.servlet.http.HttpServletResponse;
    18. import java.util.UUID;
    19. /**
    20. *

    21. * 用户信息表 服务实现类
    22. *

    23. *
    24. * @author cdl
    25. * @since 2022-11-05
    26. */
    27. @Service
    28. public class UserServiceImpl extends ServiceImpl implements IUserService {
    29. @Autowired
    30. private UserMapper userMapper;
    31. @Autowired
    32. private IRedisService redisService;
    33. @Override
    34. public JsonResponseBody userLogin(UserDto userDto, HttpServletRequest req, HttpServletResponse resp) {
    35. //要做的事情:
    36. // 判断mobile和password是否为空 已由JSP303完成(在controller中的UserDto添加@Valid便可解决)
    37. //判断mobile格式是否正确 (自定义验证注解@IsMobile)
    38. //根据用户手机号码查询用户
    39. User user = userMapper.selectOne(new QueryWrapper()
    40. .eq("id", userDto.getMobile()));
    41. // 判断所查询的用户是否存在(校验账号)
    42. if(null==user)
    43. throw new BusinessException(JsonResponseStatus.USER_USERNAME_ERROR);
    44. //前台传递到后台的密码 要经过工具类MD5加密一次才有可能跟数据库密码匹配上
    45. String pwd = MD5Utils.formPassToDbPass(userDto.getPassword(), user.getSalt());
    46. //校验密码
    47. if(!user.getPassword().equals(pwd))
    48. throw new BusinessException(JsonResponseStatus.USER_PASSWORD_ERROR);
    49. //将登陆用户对象与token令牌进行绑定保存到cookie和redis
    50. //创建登陆令牌token
    51. String token= UUID.randomUUID().toString().replace("-","");
    52. //将token令牌保存到cookie中
    53. CookieUtils.setCookie(req,resp,"token",token,7200);
    54. //将登陆token令牌与用户对象user绑定到redis中
    55. redisService.setUserToRedis(token,user);
    56. //将用户登陆的昵称设置到cookie中
    57. CookieUtils.setCookie(req,resp,"nickname",user.getNickname());
    58. return new JsonResponseBody<>();
    59. }
    60. }

    IRedisService

    1. package com.cdl.spbootpro.service;
    2. import com.cdl.spbootpro.model.User;
    3. /**
    4. * @author cdl
    5. * @site www.cdl.com
    6. * @create 2022-11-06 0:43
    7. */
    8. public interface IRedisService {
    9. //存贮数据
    10. void setUserToRedis(String token, User user);
    11. User getUserToRedis(String token);
    12. }

     IRedisServiceImpl 

    1. package com.cdl.spbootpro.service.impl;
    2. import com.cdl.spbootpro.model.User;
    3. import com.cdl.spbootpro.service.IRedisService;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.data.redis.core.RedisTemplate;
    6. import org.springframework.stereotype.Service;
    7. import java.util.concurrent.TimeUnit;
    8. /**
    9. * @author cdl
    10. * @site www.cdl.com
    11. * @create 2022-11-06 0:45
    12. */
    13. @Service
    14. public class IRedisServiceImpl implements IRedisService {
    15. @Autowired
    16. private RedisTemplate redisTemplate;
    17. @Override
    18. public void setUserToRedis(String token, User user) {
    19. redisTemplate.opsForValue().set("user:"+token,user,7200L, TimeUnit.SECONDS);//进reids
    20. }
    21. @Override
    22. public User getUserToRedis(String token) {
    23. User user = (User) redisTemplate.opsForValue().get("user:" + token);
    24. return user;
    25. }
    26. }

    运行

     

     用的工具类

    utils下

    CookieUtils 

    1. package com.cdl.spbootpro.utils;
    2. import lombok.extern.slf4j.Slf4j;
    3. import javax.servlet.http.Cookie;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.UnsupportedEncodingException;
    7. import java.net.URLDecoder;
    8. import java.net.URLEncoder;
    9. @Slf4j
    10. public class CookieUtils {
    11. /**
    12. *
    13. * @Description: 得到Cookie的值, 不编码
    14. * @param request
    15. * @param cookieName
    16. * @return
    17. */
    18. public static String getCookieValue(HttpServletRequest request, String cookieName) {
    19. return getCookieValue(request, cookieName, false);
    20. }
    21. /**
    22. *
    23. * @Description: 得到Cookie的值
    24. * @param request
    25. * @param cookieName
    26. * @param isDecoder
    27. * @return
    28. */
    29. public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
    30. Cookie[] cookieList = request.getCookies();
    31. if (cookieList == null || cookieName == null) {
    32. return null;
    33. }
    34. String retValue = null;
    35. try {
    36. for (int i = 0; i < cookieList.length; i++) {
    37. if (cookieList[i].getName().equals(cookieName)) {
    38. if (isDecoder) {
    39. retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
    40. } else {
    41. retValue = cookieList[i].getValue();
    42. }
    43. break;
    44. }
    45. }
    46. } catch (UnsupportedEncodingException e) {
    47. e.printStackTrace();
    48. }
    49. return retValue;
    50. }
    51. /**
    52. *
    53. * @Description: 得到Cookie的值
    54. * @param request
    55. * @param cookieName
    56. * @param encodeString
    57. * @return
    58. */
    59. public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
    60. Cookie[] cookieList = request.getCookies();
    61. if (cookieList == null || cookieName == null) {
    62. return null;
    63. }
    64. String retValue = null;
    65. try {
    66. for (int i = 0; i < cookieList.length; i++) {
    67. if (cookieList[i].getName().equals(cookieName)) {
    68. retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
    69. break;
    70. }
    71. }
    72. } catch (UnsupportedEncodingException e) {
    73. e.printStackTrace();
    74. }
    75. return retValue;
    76. }
    77. /**
    78. *
    79. * @Description: 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
    80. * @param request
    81. * @param response
    82. * @param cookieName
    83. * @param cookieValue
    84. */
    85. public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
    86. String cookieValue) {
    87. setCookie(request, response, cookieName, cookieValue, -1);
    88. }
    89. /**
    90. *
    91. * @Description: 设置Cookie的值 在指定时间内生效,但不编码
    92. * @param request
    93. * @param response
    94. * @param cookieName
    95. * @param cookieValue
    96. * @param cookieMaxage
    97. */
    98. public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
    99. String cookieValue, int cookieMaxage) {
    100. setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
    101. }
    102. /**
    103. *
    104. * @Description: 设置Cookie的值 不设置生效时间,但编码
    105. * 在服务器被创建,返回给客户端,并且保存客户端
    106. * 如果设置了SETMAXAGE(int seconds),会把cookie保存在客户端的硬盘中
    107. * 如果没有设置,会默认把cookie保存在浏览器的内存中
    108. * 一旦设置setPath():只能通过设置的路径才能获取到当前的cookie信息
    109. * @param request
    110. * @param response
    111. * @param cookieName
    112. * @param cookieValue
    113. * @param isEncode
    114. */
    115. public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
    116. String cookieValue, boolean isEncode) {
    117. setCookie(request, response, cookieName, cookieValue, -1, isEncode);
    118. }
    119. /**
    120. *
    121. * @Description: 设置Cookie的值 在指定时间内生效, 编码参数
    122. * @param request
    123. * @param response
    124. * @param cookieName
    125. * @param cookieValue
    126. * @param cookieMaxage
    127. * @param isEncode
    128. */
    129. public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
    130. String cookieValue, int cookieMaxage, boolean isEncode) {
    131. doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
    132. }
    133. /**
    134. *
    135. * @Description: 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
    136. * @param request
    137. * @param response
    138. * @param cookieName
    139. * @param cookieValue
    140. * @param cookieMaxage
    141. * @param encodeString
    142. */
    143. public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
    144. String cookieValue, int cookieMaxage, String encodeString) {
    145. doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
    146. }
    147. /**
    148. *
    149. * @Description: 删除Cookie带cookie域名
    150. * @param request
    151. * @param response
    152. * @param cookieName
    153. */
    154. public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
    155. String cookieName) {
    156. doSetCookie(request, response, cookieName, null, -1, false);
    157. }
    158. /**
    159. *
    160. * @Description: 设置Cookie的值,并使其在指定时间内生效
    161. * @param request
    162. * @param response
    163. * @param cookieName
    164. * @param cookieValue
    165. * @param cookieMaxage cookie生效的最大秒数
    166. * @param isEncode
    167. */
    168. private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
    169. String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
    170. try {
    171. if (cookieValue == null) {
    172. cookieValue = "";
    173. } else if (isEncode) {
    174. cookieValue = URLEncoder.encode(cookieValue, "utf-8");
    175. }
    176. Cookie cookie = new Cookie(cookieName, cookieValue);
    177. if (cookieMaxage > 0)
    178. cookie.setMaxAge(cookieMaxage);
    179. if (null != request) {// 设置域名的cookie
    180. String domainName = getDomainName(request);
    181. log.info("========== domainName: {} ==========", domainName);
    182. if (!"localhost".equals(domainName)) {
    183. cookie.setDomain(domainName);
    184. }
    185. }
    186. cookie.setPath("/");
    187. response.addCookie(cookie);
    188. } catch (Exception e) {
    189. e.printStackTrace();
    190. }
    191. }
    192. /**
    193. *
    194. * @Description: 设置Cookie的值,并使其在指定时间内生效
    195. * @param request
    196. * @param response
    197. * @param cookieName
    198. * @param cookieValue
    199. * @param cookieMaxage cookie生效的最大秒数
    200. * @param encodeString
    201. */
    202. private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
    203. String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
    204. try {
    205. if (cookieValue == null) {
    206. cookieValue = "";
    207. } else {
    208. cookieValue = URLEncoder.encode(cookieValue, encodeString);
    209. }
    210. Cookie cookie = new Cookie(cookieName, cookieValue);
    211. if (cookieMaxage > 0)
    212. cookie.setMaxAge(cookieMaxage);
    213. if (null != request) {// 设置域名的cookie
    214. String domainName = getDomainName(request);
    215. log.info("========== domainName: {} ==========", domainName);
    216. if (!"localhost".equals(domainName)) {
    217. cookie.setDomain(domainName);
    218. }
    219. }
    220. cookie.setPath("/");
    221. response.addCookie(cookie);
    222. } catch (Exception e) {
    223. e.printStackTrace();
    224. }
    225. }
    226. /**
    227. *
    228. * @Description: 得到cookie的域名
    229. * @return
    230. */
    231. private static final String getDomainName(HttpServletRequest request) {
    232. String domainName = null;
    233. String serverName = request.getRequestURL().toString();
    234. if (serverName == null || serverName.equals("")) {
    235. domainName = "";
    236. } else {
    237. serverName = serverName.toLowerCase();
    238. serverName = serverName.substring(7);
    239. final int end = serverName.indexOf("/");
    240. serverName = serverName.substring(0, end);
    241. if (serverName.indexOf(":") > 0) {
    242. String[] ary = serverName.split("\\:");
    243. serverName = ary[0];
    244. }
    245. final String[] domains = serverName.split("\\.");
    246. int len = domains.length;
    247. if (len > 3 && !isIp(serverName)) {
    248. // www.xxx.com.cn
    249. domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
    250. } else if (len <= 3 && len > 1) {
    251. // xxx.com or xxx.cn
    252. domainName = "." + domains[len - 2] + "." + domains[len - 1];
    253. } else {
    254. domainName = serverName;
    255. }
    256. }
    257. return domainName;
    258. }
    259. public static String trimSpaces(String IP){//去掉IP字符串前后所有的空格
    260. while(IP.startsWith(" ")){
    261. IP= IP.substring(1,IP.length()).trim();
    262. }
    263. while(IP.endsWith(" ")){
    264. IP= IP.substring(0,IP.length()-1).trim();
    265. }
    266. return IP;
    267. }
    268. public static boolean isIp(String IP){//判断是否是一个IP
    269. boolean b = false;
    270. IP = trimSpaces(IP);
    271. if(IP.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")){
    272. String s[] = IP.split("\\.");
    273. if(Integer.parseInt(s[0])<255)
    274. if(Integer.parseInt(s[1])<255)
    275. if(Integer.parseInt(s[2])<255)
    276. if(Integer.parseInt(s[3])<255)
    277. b = true;
    278. }
    279. return b;
    280. }
    281. }

     DataUtils 

    1. package com.cdl.spbootpro.utils;
    2. import java.util.ArrayList;
    3. import java.util.HashMap;
    4. import java.util.List;
    5. import java.util.Map;
    6. public class DataUtils {
    7. /**
    8. * 转换方法,基于商品的排版情况(一行三列、一行四列等等)进行数据分行处理
    9. * @param cols 一行显示几列
    10. * @param goods 需要筛选的数据集
    11. * @return
    12. */
    13. public Map> transfor(int cols, List goods){
    14. Map> data=new HashMap<>();
    15. List rs=new ArrayList<>();
    16. int len=goods.size();
    17. for (int i = 0; i < len; i++) {
    18. rs.add(goods.get(i));
    19. if((i+1)%cols==0){
    20. data.put("goods"+(i+1),rs);
    21. if(i==len-1)
    22. break;
    23. rs=new ArrayList<>();
    24. continue;
    25. }
    26. if(i==len-1){
    27. data.put("goods"+(i+1),rs);
    28. }
    29. }
    30. return data;
    31. }
    32. }

     JsonResponseBody

    1. package com.cdl.spbootpro.utils;
    2. import lombok.Data;
    3. import java.io.Serializable;
    4. /**
    5. * 响应封装类
    6. */
    7. @Data
    8. public class JsonResponseBody implements Serializable {
    9. private String msg="OK";
    10. private T data;
    11. private Integer code;
    12. private Integer total;
    13. public JsonResponseBody(){
    14. this.data=null;
    15. this.code=JsonResponseStatus.SUCCESS.getCode();
    16. }
    17. public JsonResponseBody(T data){
    18. this.data=data;
    19. this.code=JsonResponseStatus.SUCCESS.getCode();
    20. }
    21. public JsonResponseBody(T data,Integer total){
    22. this.data=data;
    23. this.total=total;
    24. this.code=JsonResponseStatus.SUCCESS.getCode();
    25. }
    26. public JsonResponseBody(JsonResponseStatus jsonResponseStatus){
    27. this.msg=jsonResponseStatus.getMsg();
    28. this.code=jsonResponseStatus.getCode();
    29. }
    30. public JsonResponseBody(JsonResponseStatus jsonResponseStatus,T data){
    31. this.data=data;
    32. this.msg=jsonResponseStatus.getMsg();
    33. this.code=jsonResponseStatus.getCode();
    34. }
    35. }

     JsonResponseStatus

    1. package com.cdl.spbootpro.utils;
    2. import lombok.AllArgsConstructor;
    3. import lombok.Getter;
    4. import lombok.ToString;
    5. @Getter
    6. @ToString
    7. @AllArgsConstructor
    8. public enum JsonResponseStatus {
    9. SUCCESS(200,"OK"),
    10. ERROR(500,"内部错误"),
    11. USER_LOGIN_ERROR(100101,"用户名或者密码错误"),
    12. USER_MOBILE_ERROR(100102,"手机号码格式错误"),
    13. USER_PASSWORD_ERROR(100103,"用户密码错误"),
    14. USER_USERNAME_ERROR(100104,"账号不存在"),
    15. BIND_ERROR(200101,"参数校验异常"),
    16. TOKEN_EEROR(200102,"token令牌失效或已过期")
    17. ;
    18. private final Integer code;
    19. private final String msg;
    20. }

     MD5Utils 

    1. package com.cdl.spbootpro.utils;
    2. import org.apache.commons.codec.digest.DigestUtils;
    3. import org.springframework.stereotype.Component;
    4. import java.util.UUID;
    5. /**
    6. * MD5加密
    7. * 用户端:password=MD5(明文+固定Salt)
    8. * 服务端:password=MD5(用户输入+随机Salt)
    9. * 用户端MD5加密是为了防止用户密码在网络中明文传输,服务端MD5加密是为了提高密码安全性,双重保险。
    10. */
    11. @Component
    12. public class MD5Utils {
    13. //加密盐,与前端一致
    14. private static String salt="f1g2h3j4";
    15. /**
    16. * md5加密
    17. * @param src
    18. * @return
    19. */
    20. public static String md5(String src){
    21. return DigestUtils.md5Hex(src);
    22. }
    23. /**
    24. * 获取加密的盐
    25. * @return
    26. */
    27. public static String createSalt(){
    28. return UUID.randomUUID().toString().replace("-","");
    29. }
    30. /**
    31. * 将前端的明文密码通过MD5加密方式加密成后端服务所需密码
    32. * 注意:该步骤实际是在前端完成!!!
    33. * @param inputPass 明文密码
    34. * @return
    35. */
    36. public static String inputPassToFormpass(String inputPass){
    37. //混淆固定盐salt,安全性更可靠
    38. String str=salt.charAt(1)+""+salt.charAt(5)+inputPass+salt.charAt(0)+""+salt.charAt(3);
    39. return md5(str);
    40. }
    41. /**
    42. * 将后端密文密码+随机salt生成数据库的密码
    43. * @param formPass
    44. * @param salt
    45. * @return
    46. */
    47. public static String formPassToDbPass(String formPass,String salt){
    48. //混淆固定盐salt,安全性更可靠
    49. String str=salt.charAt(7)+""+salt.charAt(4)+formPass+salt.charAt(1)+""+salt.charAt(5);
    50. return md5(str);
    51. }
    52. /**
    53. * 将用户输入的密码转换成数据库的密码
    54. * @param inputPass 明文密码
    55. * @param salt 盐
    56. * @return
    57. */
    58. public static String inputPassToDbPass(String inputPass,String salt){
    59. String formPass = inputPassToFormpass(inputPass);
    60. String dbPass = formPassToDbPass(formPass, salt);
    61. return dbPass;
    62. }
    63. public static void main(String[] args) {
    64. //d7aaa28e3b8e6c88352bd5e7c23829f9
    65. //5512a78a188b318c074a15f9b056a712
    66. String formPass = inputPassToFormpass("123456");
    67. System.out.println("前端加密密码:"+formPass);
    68. String salt = createSalt();
    69. System.out.println("后端加密随机盐:"+salt);
    70. String dbPass = formPassToDbPass(formPass, salt);
    71. System.out.println("后端加密密码:"+dbPass);
    72. System.out.println("-------------------------------------------");
    73. String dbPass1 = inputPassToDbPass("123456", salt);
    74. System.out.println("最终加密密码:"+dbPass1);
    75. }
    76. }

     MybatisPlusConfig 

    1. package com.cdl.spbootpro.utils;
    2. import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
    3. import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
    4. import org.mybatis.spring.annotation.MapperScan;
    5. import org.springframework.context.annotation.Bean;
    6. import org.springframework.context.annotation.Configuration;
    7. import org.springframework.transaction.annotation.EnableTransactionManagement;
    8. //Spring boot方式
    9. @EnableTransactionManagement
    10. @Configuration
    11. @MapperScan("com.cdl.shoppingpro.service.*.mapper*")
    12. public class MybatisPlusConfig {
    13. @Bean
    14. public PaginationInterceptor paginationInterceptor() {
    15. PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
    16. // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
    17. // paginationInterceptor.setOverflow(false);
    18. // 设置最大单页限制数量,默认 500 条,-1 不受限制
    19. // paginationInterceptor.setLimit(500);
    20. // 开启 count 的 join 优化,只针对部分 left join
    21. paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
    22. return paginationInterceptor;
    23. }
    24. }

     PageBean 

    1. package com.cdl.spbootpro.utils;
    2. import javax.servlet.http.HttpServletRequest;
    3. import java.io.Serializable;
    4. import java.util.Map;
    5. public class PageBean implements Serializable {
    6. //页码
    7. private int page=1;
    8. //每页显示条数
    9. private int rows=10;
    10. //总记录数
    11. private int total=0;
    12. //是否分页标记
    13. private boolean pagination=true;
    14. //上一次请求的路径
    15. private String url;
    16. //请求参数Map集合
    17. private Map map;
    18. public String getUrl() {
    19. return url;
    20. }
    21. public void setUrl(String url) {
    22. this.url = url;
    23. }
    24. public Map getMap() {
    25. return map;
    26. }
    27. public void setMap(Map map) {
    28. this.map = map;
    29. }
    30. public int getPage() {
    31. return page;
    32. }
    33. public void setPage(int page) {
    34. this.page = page;
    35. }
    36. public int getRows() {
    37. return rows;
    38. }
    39. public void setRows(int rows) {
    40. this.rows = rows;
    41. }
    42. public int getTotal() {
    43. return total;
    44. }
    45. public void setTotal(int total) {
    46. this.total = total;
    47. }
    48. public boolean isPagination() {
    49. return pagination;
    50. }
    51. public void setPagination(boolean pagination) {
    52. this.pagination = pagination;
    53. }
    54. //重载setPage/setRows/setPagination方法
    55. public void setPage(String page) {
    56. if(null!=page&&!"".equals(page))
    57. this.page=Integer.parseInt(page);
    58. }
    59. public void setRows(String rows) {
    60. if(null!=rows&&!"".equals(rows))
    61. this.rows=Integer.parseInt(rows);
    62. }
    63. public void setPagination(String pagination) {
    64. if(null!=pagination&&!"".equals(pagination))
    65. this.pagination=Boolean.parseBoolean(pagination);
    66. }
    67. public void setRequest(HttpServletRequest req) {
    68. //获取前端提交的page/rows/pagination参数
    69. String page=req.getParameter("page");
    70. String rows=req.getParameter("rows");
    71. String pagination=req.getParameter("pagination");
    72. //设置属性
    73. this.setPage(page);
    74. this.setPagination(pagination);
    75. this.setRows(rows);
    76. //设置上一次请求的路径
    77. //第一次请求:
    78. //http://localhost:8080/项目名/请求路径.action?page=1
    79. //第二次请求:下一页 page=2
    80. //项目名+请求路径.action
    81. //req.getContextPath()+req.getServletPath()==req.getRequestURI()
    82. this.url=req.getRequestURI();
    83. //获取请求参数集合
    84. // checkbox name='hobby'
    85. // Map hobby==key value==new String[]{"篮球","足球",..}
    86. this.map=req.getParameterMap();
    87. }
    88. /**
    89. * 获取分页的起始位置
    90. * @return
    91. */
    92. public int getStartIndex() {
    93. //第1页:(1-1)*10 ==0 limit 0,10
    94. //第2页:(2-1)*10 ==10 limit 10,10
    95. //..
    96. return (this.page-1)*this.rows;
    97. }
    98. //获取末页、上一页、下一页
    99. /**
    100. * 获取末页
    101. * @return
    102. */
    103. public int getMaxPager() {
    104. int maxPager=this.total/this.rows;
    105. if(this.total%this.rows!=0)
    106. maxPager++;
    107. return maxPager;
    108. }
    109. /**
    110. * 获取上一页
    111. * @return
    112. */
    113. public int getPreviousPager() {
    114. int previousPager=this.page-1;
    115. if(previousPager<=1)
    116. previousPager=1;
    117. return previousPager;
    118. }
    119. /**
    120. * 获取下一页
    121. * @return
    122. */
    123. public int getNextPager() {
    124. int nextPager=this.page+1;
    125. if(nextPager>getMaxPager())
    126. nextPager=getMaxPager();
    127. return nextPager;
    128. }
    129. @Override
    130. public String toString() {
    131. return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination
    132. + ", url=" + url + ", map=" + map + "]";
    133. }
    134. }

     ValidatorUtils 

    1. package com.cdl.spbootpro.utils;
    2. import org.apache.commons.lang3.StringUtils;
    3. import java.util.regex.Matcher;
    4. import java.util.regex.Pattern;
    5. /**
    6. * 正则校验工具类
    7. * @author 刘开宇
    8. */
    9. public class ValidatorUtils {
    10. private static final Pattern mobile_pattern=Pattern.compile("[1]([0-9])[0-9]{9}$");
    11. public static boolean isMobile(String mobile){
    12. if(StringUtils.isEmpty(mobile))
    13. return false;
    14. Matcher matcher = mobile_pattern.matcher(mobile);
    15. return matcher.matches();
    16. }
    17. }

  • 相关阅读:
    【Linux】软件包管理器yum
    Netty入门指南之NIO Selector监管
    Zookeeper:分布式过程协同技术
    恶意软件通杀 Win、macOS、Linux 三大系统;唱片巨头起诉 Youtube-dl 的托管服务商;2022 年不是 Linux 桌面元年 | 开源日报
    (四)GIT系列——GitLab备份与恢复
    CCF CSP题解:数字排序(201503-2)
    cesium 自定义气泡 类
    ubuntu下yolov5 tensorrt模型部署
    六、SSL开源项目-Open虚拟私有网络
    2022年6月 电子学会青少年软件编程 中小学生Python编程 等级考试一级真题答案解析(判断题)
  • 原文地址:https://blog.csdn.net/weixin_62735525/article/details/127705240