日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

乐优商城(11)--用户中心

發布時間:2023/12/10 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 乐优商城(11)--用户中心 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

樂優商城(11)–用戶中心

一、創建用戶中心

用戶搜索到自己心儀的商品,接下來就要去購買,但是購買必須先登錄。所以要創建用戶中心,實現用戶的登錄和注冊功能。

用戶中心的提供的服務:

  • 用戶的注冊
  • 用戶登錄
  • 用戶個人信息管理
  • 用戶地址管理
  • 用戶收藏管理
  • 我的訂單
  • 優惠券管理

這里暫時先實現基本的功能:登錄和注冊。

因為用戶中心的服務其它微服務也會調用,因此這里需要做聚合。

leyou-user:父工程,包含2個子工程:

  • leyou-user-interface:實體及接口

  • leyou-user-service:業務和服務

1.1、創建父module

1.2、創建leyou-user-interface

在leyou-user下,創建module:

1.3、創建leyou-user-service

pom文件:

<?xml version="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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>leyou-user</artifactId><groupId>com.leyou.user</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>leyou-user-service</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- mybatis啟動器 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!-- 通用Mapper啟動器 --><dependency><groupId>tk.mybatis</groupId><artifactId>mapper-spring-boot-starter</artifactId></dependency><!-- mysql驅動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.leyou.user</groupId><artifactId>leyou-user-interface</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies></project>

啟動類:

@SpringBootApplication @EnableDiscoveryClient @MapperScan("com.leyou.user.mapper") public class LeyouUserApplication {public static void main(String[] args) {SpringApplication.run(LeyouUserApplication.class,args);} }

配置文件

server:port: 8085 spring:application:name: user-servicedatasource:url: jdbc:mysql://127.0.0.1:3306/leyouusername: rootpassword: 123456hikari:max-lifetime: 28830000 # 一個連接的生命時長(毫秒),超時而且沒被使用則被釋放(retired),缺省:30分鐘,建議設置比數據庫超時時長少30秒,參考MySQL wait_timeout參數(show variables like '%timeout%';)maximum-pool-size: 9 # 連接池中允許的最大連接數。缺省值:10;推薦的公式:((core_count * 2) + effective_spindle_count)driver-class-name: com.mysql.jdbc.Drivercloud:nacos:discovery:server-addr: ip地址:8848username: nacospassword: nacos mybatis:type-aliases-package: com.leyou.user.pojo

1.4、添加網關路由

修改leyou-gateway,添加路由規則,對leyou-user-service進行路由:

二、后臺功能準備

2.1、數據庫表結構

CREATE TABLE `tb_user` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`username` varchar(50) NOT NULL COMMENT '用戶名',`password` varchar(32) NOT NULL COMMENT '密碼,加密存儲',`phone` varchar(20) DEFAULT NULL COMMENT '注冊手機號',`created` datetime NOT NULL COMMENT '創建時間',`salt` varchar(32) NOT NULL COMMENT '密碼加密的salt值',PRIMARY KEY (`id`),UNIQUE KEY `username` (`username`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8 COMMENT='用戶表';

數據結構比較簡單,因為根據用戶名查詢的頻率較高,所以給用戶名創建了索引

2.2、基本代碼

2.2.1、實體類

@Table(name = "tb_user") public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String username;// 用戶名@JsonIgnoreprivate String password;// 密碼private String phone;// 電話private Date created;// 創建時間@JsonIgnoreprivate String salt;// 密碼的鹽值 }

注意:出于安全考慮。這里對password和salt添加了注解@JsonIgnore,這樣在json序列化時,就不會把password和salt返回。

2.2.2、mapper

/*** User 的通用 mapper*/ public interface UserMapper extends Mapper<User> { }

2.2.3、Service

public interface UserService { }

實現類:

@Service public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper; }

2.2.4、controller

@RestController @RequestMapping("/user") public class UserController {@Autowiredprivate UserService userService;}

三、數據驗證功能

3.1、接口說明

實現用戶數據的校驗,主要包括對:電子郵箱、用戶名的唯一性校驗。

接口路徑:

GET /check/{data}/{type}

參數說明:

參數說明是否必須數據類型默認值
data要校驗的數據String
type要校驗的數據類型:1,用戶名;2,電子郵箱;Integer1

返回結果:

返回布爾類型結果:

  • true:可用
  • false:不可用

狀態碼:

  • 200:校驗成功
  • 400:參數有誤
  • 500:服務器內部異常

3.2、controller

因為有了接口,可以不關心頁面,所有需要的東西都一清二楚:

  • 請求方式:GET
  • 請求路徑:/check/{param}/{type}
  • 請求參數:param,type
  • 返回結果:true或false
/*** 用戶注冊時電子郵箱、用戶名的唯一性校驗* @param data* @param type* @return*/ @GetMapping("/check/{data}/{type}") public ResponseEntity<Boolean> checkUserData(@PathVariable("data") String data,@PathVariable("type") Integer type){Boolean bool = this.userService.checkUserData(data,type);if (null == bool) return ResponseEntity.badRequest().build();return ResponseEntity.ok(bool); }

3.3、Service

/*** 對電子郵箱、用戶名的唯一性校驗* @param data* @param type* @return*/ Boolean checkUserData(String data, Integer type);

實現類:

/*** 對電子郵箱、用戶名的唯一性校驗** @param data* @param type* @return*/ @Override public Boolean checkUserData(String data, Integer type) {User user = new User();if (type == 1){user.setUsername(data);}else if (type == 2){user.setPhone(data);}else {return null;}//為0說明數據庫中不存在該數據,可以注冊return this.userMapper.selectCount(user) == 0; }

3.4、測試

在數據庫插入一條數據:

然后在瀏覽器調用接口,測試:

四、郵件服務

4.1、創建郵件微服務

因為系統中不止注冊一個地方需要郵件發送,因此將郵件發送抽取為微服務:leyou-sms-service,凡是需要的地方都可以使用。

另外,因為郵件發送API調用時長的不確定性,為了提高程序的響應速度,短信發送將采用異步發送方式,即:

  • 郵件服務監聽MQ消息,收到消息后發送短信。
  • 其它服務要發送短信時,通過MQ通知短信微服務。

注:阿里云短信服務個人不可用,申請需要提供相關證明資料,這里使用郵件服務替代

4.1.1、開啟QQ郵件服務

  • 開啟QQPOP3/SMTP服務

  • 按提示完成相關操作后會得到一份授權碼,妥善保存

  • 在配置文件中添加配置

  • 4.1.2、創建module

    4.1.3、pom文件

    <?xml version="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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>myLeyou</artifactId><groupId>com.leyou.parent</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.leyou.sms</groupId><artifactId>leyou-sms-service</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency></dependencies></project>

    4.1.4、編寫啟動類

    @SpringBootApplication public class LeyouSmsApplication {public static void main(String[] args) {SpringApplication.run(LeyouSmsApplication.class,args);} }

    4.1.5、編寫application.yml

    server:port: 8086 spring:application:name: sms-servicerabbitmq:host: 192.168.56.101username: leyoupassword: leyouvirtual-host: /leyoumail:host: smtp.qq.comusername: xxxxxxxxx@qq.com #自己的郵箱地址password: xxxxxxxxxxxxx #郵箱授權碼default-encoding: UTF-8protocol: smtpport: 25

    4.2、編寫郵件工具類

    package com.leyou.sms.utils;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component;import javax.mail.MessagingException; import javax.mail.internet.MimeMessage;@Component public class SmsUtils {@Autowiredprivate JavaMailSender javaMailSender;/*** 給用戶的郵箱發送驗證碼* @param email* @param code* @throws MessagingException*/public void sendMailMessage(String email,String code) throws MessagingException {MimeMessage mimeMessage = this.javaMailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);helper.setSubject("【樂優商城】驗證");helper.setText("<p>您好 [" + email + "]</p><p>您的驗證碼為 "+code+"。</p>" +"<p>驗證碼5分鐘內有效!</p>" +"<p>如非本人操作,請忽略本郵件</p>" +"<p>[本郵件由系統自動發送,請勿直接回復]</p>",true);helper.setFrom("xxxxxxxxx@qq.com"); //這里填寫開啟郵件服務的QQ號碼helper.setTo(email);this.javaMailSender.send(mimeMessage);} }

    4.3、編寫消息監聽器

    接下來,編寫消息監聽器,當接收到消息后,發送短信。

    @Component public class SmsListener {@Autowiredprivate SmsUtils smsUtils;@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "leyou.sms.queue",durable = "true"),exchange = @Exchange(value = "leyou.sms.exchange",ignoreDeclarationExceptions = "true"),key = {"sms.verify.code"}))public void listenSms(Map<String,String> msg) throws MessagingException {//如果msg為空 不處理if (msg == null || msg.size() <= 0) return;String email = msg.get("email");String code = msg.get("code");//email 或者 驗證碼為空 不處理if (StringUtils.isEmpty(email) || StringUtils.isEmpty(code)) return;//發送郵箱驗證碼this.smsUtils.sendMailMessage(email,code);} }

    測試

    啟動項目,然后查看RabbitMQ控制臺,發現交換機已經創建:

    五、發送郵件功能

    5.1、生成郵件驗證碼

    功能說明

    根據用戶輸入的電子郵箱,生成隨機驗證碼,長度為6位,純數字。并且調用郵件服務,發送驗證碼到用戶的電子郵箱。

    接口路徑

    POST /code

    參數說明:

    參數說明是否必須數據類型默認值
    phone用戶的手機號碼String

    **返回結果:**無

    狀態碼:

    • 204:請求已接收
    • 400:參數有誤
    • 500:服務器內部異常

    業務邏輯:

    • 1)接收頁面發送來的手機號碼
    • 2)生成一個隨機驗證碼
    • 3)將驗證碼保存在服務端
    • 4)發送短信,將驗證碼發送到用戶手機

    那么問題來了:驗證碼保存在哪里呢?

    驗證碼有一定有效期,一般是5分鐘,可以利用Redis的過期機制來保存。

    5.2、Redis

    5.2.1、下載和安裝

    官網:https://redis.io/download

  • 將壓縮包上傳至/usr/local/leyou

  • 解壓

    cd /usr/local/leyou tar -xvf redis-6.0.15.tar.gz
  • 編譯安裝

    mv redis-6.0.15 redis cd redis# 編譯安裝需要gcc5.3以上,可以用gcc -v 命令查看當前版本號,使用下面的命令升級到gcc9.1: yum -y install centos-release-scl yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils #scl命令啟用只是臨時的,新開的會話默認還是原gcc版本。 scl enable devtoolset-9 bash#如果編譯出錯之后再編譯可以先執行命令刪除之前的編譯文件 make distcleanmake && make install#編譯完了可以執行命令測試 需要一定的等待時間 make test
  • 修改安裝目錄下的redis.conf文件

    vim redis.conf

    修改以下配置:

    #bind 127.0.0.1 # 將這行代碼注釋,監聽所有的ip地址,外網可以訪問 port 8975 #改成8975 protected-mode no # 把yes改成no,允許外網訪問 daemonize yes # 把no改成yes,后臺運行
  • 啟動:./src/redis-server redis.conf

  • 修改端口為8975,不使用默認端口主要原因是會有黑客攻擊阿里云服務器,植入挖礦程序,這里改變端口,安全性會提高一些,如果設置密碼會更好

  • 啟用客戶端連接,測試

  • 注:redis6之后支持多線程

    5.3、Spring Data Redis

    官網:http://projects.spring.io/spring-data-redis/

    Spring Data Redis,是Spring Data 家族的一部分。 對Jedis客戶端進行了封裝,與spring進行了整合。可以非常方便的來實現對redis的配置和操作。

    5.3.1、RedisTemplate基本操作

    Spring Data Redis 提供了一個工具類:RedisTemplate。里面封裝了對于Redis的五種數據結構的各種操作,包括:

    • redisTemplate.opsForValue() :操作字符串
    • redisTemplate.opsForHash() :操作hash
    • redisTemplate.opsForList():操作list
    • redisTemplate.opsForSet():操作set
    • redisTemplate.opsForZSet():操作zset

    其它一些通用命令,如expire,可以通過redisTemplate.xx()來直接調用

    5種結構:

    • String:等同于java中的,Map<String,String>
    • list:等同于java中的Map<String,List<String>>
    • set:等同于java中的Map<String,Set<String>>
    • sort_set:可排序的set
    • hash:等同于java中的:`Map<String,Map<String,String>>

    5.3.2、StringRedisTemplate

    RedisTemplate在創建時,可以指定其泛型類型:

    • K:代表key 的數據類型
    • V: 代表value的數據類型

    注意:這里的類型不是Redis中存儲的數據類型,而是Java中的數據類型,RedisTemplate會自動將Java類型轉為Redis支持的數據類型:字符串、字節、二進制等等。

    不過RedisTemplate默認會采用JDK自帶的序列化(Serialize)來對對象進行轉換。生成的數據十分龐大,因此通常都會指定key和value為String類型,這樣就可以把對象序列化為json字符串來存儲。

    Spring默認提供了這樣一個實現: StringRedisTemplate,它是繼承RedisTemplate<String,String>

    5.4、項目實現

    需要三個步驟:

    • 生成隨機驗證碼
    • 將驗證碼保存到Redis中,用來在注冊的時候驗證
    • 發送驗證碼到leyou-sms-service服務,發送短信

    引入依賴:

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

    添加RabbitMQ和Redis配置:

    spring:redis:host: 192.168.56.101port: 8975rabbitmq:virtual-host: /leyouusername: leyoupassword: leyouhost: 192.168.56.101

    另外還要用到工具類,生成6位隨機碼,這個封裝到了leyou-common中,因此需要引入依賴:

    <dependency><groupId>com.leyou.common</groupId><artifactId>leyou-common</artifactId><version>0.0.1-SNAPSHOT</version> </dependency>

    NumberUtils中有生成隨機碼的工具方法:

    /*** 生成指定位數的隨機數字* @param len 隨機數的位數* @return 生成的隨機數*/ public static String generateCode(int len){len = Math.min(len, 8);int min = Double.valueOf(Math.pow(10, len - 1)).intValue();int num = new Random().nextInt(Double.valueOf(Math.pow(10, len + 1)).intValue() - 1) + min;return String.valueOf(num).substring(0,len); }

    UserController

    在leyou-user-service工程中的UserController添加方法:

    /*** 發送郵箱驗證碼* @param email* @return*/ @PostMapping("/code") public ResponseEntity<Void> sendVerifyCode(@RequestParam("phone") String email){Boolean bool = this.userService.sendVerifyCode(email);if (null == bool || !bool){return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();}return ResponseEntity.status(HttpStatus.CREATED).build(); }

    UserService

    /*** 發送郵箱驗證碼* @param email* @return*/ Boolean sendVerifyCode(String email);

    實現類:

    @Autowired private AmqpTemplate amqpTemplate;@Autowired private StringRedisTemplate redisTemplate;private final static String KEY_PREFIX = "user:code:email:";private final static Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class); /*** 發送郵箱驗證碼** @param email* @return*/ @Override public Boolean sendVerifyCode(String email) {//校驗email是否為空if(StringUtils.isBlank(email)) return false;//生成郵箱驗證碼String code = NumberUtils.generateCode(6);try {//將消息發送給mq,發送郵箱驗證碼Map<String, String> msg = new HashMap<>();msg.put("email",email);msg.put("code",code);this.amqpTemplate.convertAndSend("leyou.sms.exchange","sms.verify.code",msg);//存入redis 并指定過期時間為5分鐘this.redisTemplate.opsForValue().set(KEY_PREFIX+email,code,5, TimeUnit.MINUTES);return true;} catch (AmqpException e) {LOGGER.error("發送郵件失敗。email:{}, code:{}", email, code);return false;} }

    測試

    通過ApiPost發送請求測試:

    查看redis中的數據:

    查看郵件:

    六、注冊功能

    6.1、接口說明

    功能說明

    實現用戶注冊功能,需要對用戶密碼進行加密存儲,使用MD5加密,加密過程中使用隨機碼作為salt加鹽。另外還需要對用戶輸入的驗證碼進行校驗。

    接口路徑

    POST /register

    參數說明:

    form表單格式

    參數說明是否必須數據類型默認值
    username用戶名,格式為4~30位字母、數字、下劃線String
    password用戶密碼,格式為4~30位字母、數字、下劃線String
    phone電子郵箱String
    code郵箱驗證碼String

    **返回結果:**無返回值。

    狀態碼:

    • 201:注冊成功
    • 400:參數有誤,注冊失敗
    • 500:服務器內部異常,注冊失敗

    業務邏輯:

    • 1)校驗郵箱驗證碼
    • 2)生成鹽
    • 3)對密碼加密
    • 4)寫入數據庫
    • 5)刪除Redis中的驗證碼

    6.2、UserController

    /*** 用戶注冊* @param user* @param code* @return*/ @PostMapping("/register") public ResponseEntity<Void> register(User user, @RequestParam("code") String code){Boolean bool = this.userService.register(user,code);if (null == bool || !bool){return ResponseEntity.badRequest().build();}return ResponseEntity.status(HttpStatus.CREATED).build(); }

    6.3、UserService

    /*** 用戶注冊* @param user* @param code* @return*/ Boolean register(User user, String code);

    實現類:

    /*** 用戶注冊** @param user* @param code* @return*/ @Override public Boolean register(User user, String code) {//從redis獲取驗證碼String cacheCode = this.redisTemplate.opsForValue().get(KEY_PREFIX + user.getPhone());//校驗驗證碼if (!StringUtils.equals(cacheCode,code)) return false;//生成鹽String salt = CodeUtils.generateSalt();user.setSlat(salt);//對密碼加密String password = CodeUtils.md5Hex(user.getPassword(), salt);//添加用戶user.setId(null);user.setCreated(new Date());user.setPassword(password);Boolean bool = this.userMapper.insertSelective(user) == 1;if (bool){//注冊成功后,刪除該驗證碼this.redisTemplate.delete(KEY_PREFIX+user.getPhone());}return bool; }

    這里使用了工具類CodeUtils:

    public class CodeUtils {public static String md5Hex(String data,String salt) {if (StringUtils.isBlank(salt)) {salt = data.hashCode() + "";}return DigestUtils.md5Hex(salt + DigestUtils.md5Hex(data));}public static String shaHex(String data, String salt) {if (StringUtils.isBlank(salt)) {salt = data.hashCode() + "";}return DigestUtils.sha512Hex(salt + DigestUtils.sha512Hex(data));}public static String generateSalt(){return StringUtils.replace(UUID.randomUUID().toString(), "-", "");} }

    6.4、測試

    通過ApiPost發送請求測試:

    查看數據庫:

    6.5、服務端數據校驗

    6.5.1、hibernate-validate

    Hibernate Validator是Hibernate提供的一個開源框架,使用注解方式非常方便的實現服務端的數據校驗。

    官網:http://hibernate.org/validator/

    SpringBoot的web啟動器中已經集成了相關依賴。

    hibernate Validator 是 Bean Validation 的參考實現 。

    Hibernate Validator 提供了 JSR 303 規范中所有內置 constraint(約束) 的實現,除此之外還有一些附加的 constraint。

    在日常開發中,Hibernate Validator經常用來驗證bean的字段,基于注解,方便快捷高效。

    6.5.2、Bean校驗的注解

    常用注解如下:

    Constraint詳細信息
    @Valid被注釋的元素是一個對象,需要檢查此對象的所有字段值
    @Null被注釋的元素必須為 null
    @NotNull被注釋的元素必須不為 null
    @AssertTrue被注釋的元素必須為 true
    @AssertFalse被注釋的元素必須為 false
    @Min(value)被注釋的元素必須是一個數字,其值必須大于等于指定的最小值
    @Max(value)被注釋的元素必須是一個數字,其值必須小于等于指定的最大值
    @DecimalMin(value)被注釋的元素必須是一個數字,其值必須大于等于指定的最小值
    @DecimalMax(value)被注釋的元素必須是一個數字,其值必須小于等于指定的最大值
    @Size(max, min)被注釋的元素的大小必須在指定的范圍內
    @Digits (integer, fraction)被注釋的元素必須是一個數字,其值必須在可接受的范圍內
    @Past被注釋的元素必須是一個過去的日期
    @Future被注釋的元素必須是一個將來的日期
    @Pattern(value)被注釋的元素必須符合指定的正則表達式
    @Email被注釋的元素必須是電子郵箱地址
    @Length被注釋的字符串的大小必須在指定的范圍內
    @NotEmpty被注釋的字符串的必須非空
    @Range被注釋的元素必須在合適的范圍內
    @NotBlank被注釋的字符串的必須非空
    @URL(protocol=,host=, port=,regexp=, flags=)被注釋的字符串必須是一個有效的url
    @CreditCardNumber被注釋的字符串必須通過Luhn校驗算法,銀行卡,信用卡等號碼一般都用Luhn計算合法性

    6.5.3、給User添加校驗

    在leyou-user-interface中添加Hibernate-Validator依賴:

    <dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId> </dependency>

    在User對象的部分屬性上添加注解:

    @Table(name = "tb_user") public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id; //用戶id@Length(min = 4,max = 30,message = "用戶名字符長度只能在4~30位之間")private String username;//用戶名@JsonIgnore //數據以json格式傳輸時 該字段不傳輸@Length(min = 6,max = 30,message = "密碼長度只能在6~30位之間")private String password;//密碼@Email(message = "郵箱格式不正確") //由于阿里云短信不可用 將手機服務全部改成郵箱服務 但字段名不變private String phone; //注冊手機號碼private Date created; //創建時間@JsonIgnore //數據以json格式傳輸時 該字段不傳輸private String salt; //密碼加密的鹽值 }

    在controller上進行控制:

    可以進行相關測試…

    七、查詢用戶

    7.1、接口說明

    功能說明

    查詢功能,根據參數中的用戶名和密碼查詢指定用戶

    接口路徑

    GET /query

    參數說明:

    form表單格式

    參數說明是否必須數據類型默認值
    username用戶名,格式為4~30位字母、數字、下劃線String
    password用戶密碼,格式為4~30位字母、數字、下劃線String

    **返回結果:**用戶的json格式數據

    {"id": 6572312,"username":"test","phone":"13688886666","created": 1342432424 }

    狀態碼:

    • 200:注冊成功
    • 400:用戶名或密碼錯誤
    • 500:服務器內部異常,注冊失敗

    7.2、Controller

    /*** 根據用戶名查詢用戶,校驗密碼* @param username* @param password* @return*/ @PostMapping("/query") public ResponseEntity<User> queryUser(@RequestParam("username") String username,@RequestParam("password") String password){User user = this.userService.queryUser(username,password);if (null == user){return ResponseEntity.badRequest().build();}return ResponseEntity.ok(user); }

    7.3、Service

    /*** 根據用戶名查詢用戶,校驗密碼* @param username* @param password* @return*/ User queryUser(String username, String password);

    實現類:

    @Override public User queryUser(String username, String password) {User record = new User();record.setUsername(username);User user = this.userMapper.selectOne(record);//校驗查詢的用戶if (null == user) return null;//將用戶傳入的密碼用鹽進行加密再與數據庫數據進行比較//對用戶輸入的密碼加鹽加密password = CodeUtils.md5Hex(password, user.getSalt());//判斷用戶輸入的密碼是否正確if (!StringUtils.equals(password, user.getPassword())) {return null;//拋出異常}return user; }

    7.4、 測試

    7.5、優化

    經常要查詢用戶信息,將用戶信息放入到redis中,直接從redis中查詢。

    改造queryUser,讓其查詢用戶信息的時候不是直接從數據庫中獲取,先從redis中查詢,查詢不到的話再去數據庫中查詢,查詢成功后再將數據放入到redis緩存中

    private final static String USER_PREFIX = "user:verify:";@Override public User queryUser(String username, String password) {/*** 邏輯改變,先去緩存中查詢用戶數據,查到的話直接返回,查不到再去數據庫中查詢,然后放入到緩存當中*///先去緩存中查詢BoundHashOperations<String, Object, Object> boundHashOps = this.redisTemplate.boundHashOps(USER_PREFIX + username);User user = (User) boundHashOps.get(username);//如果緩存中沒有查找到,則去數據庫查詢if (user == null){User recode = new User();recode.setUsername(username);user = this.userMapper.selectOne(recode);//查詢后放入緩存中boundHashOps.put(user.getUsername(),user);}//校驗查詢的用戶if (null == user) return null;//將用戶傳入的密碼用鹽進行加密再與數據庫數據進行比較//對用戶輸入的密碼加鹽加密password = CodeUtils.md5Hex(password, user.getSalt());//判斷用戶輸入的密碼是否正確if (!StringUtils.equals(password, user.getPassword())) {return null;//拋出異常}return user; }

    存在的問題

    數據不一致問題!!

    比如說用戶修改密碼,那么在后端修改數據庫時會產生一些問題。是先刪除緩存,再更新數據庫呢?還是先更新數據庫再刪除緩存?

    • 先刪除緩存,再更新數據庫

    試想,兩個并發操作,一個是更新操作,另一個是查詢操作,更新操作刪除緩存后,查詢操作沒有命中緩存,先把老數據讀出來后放到緩存中,然后更新操作更新了數據庫。于是,在緩存中的數據還是老的數據,導致緩存中的數據是臟的,而且還一直這樣臟下去。

    • 先更新數據庫,再刪除緩存。這是常規做法,緩存基于數據庫,取自數據庫

    @Override public Boolean updatePassword(String username, String password, String newPassword) {/*** 這里面涉及到對緩存的操作:* 先把數據存到數據庫中,成功后,再讓緩存失效。*///獲取用戶的信息User user = query(username, password);if (user == null) return false;//修改用戶的密碼User record = new User();record.setId(user.getId());//將新密碼加密newPassword = CodecUtils.md5Hex(newPassword,user.getSalt());record.setPassword(newPassword);this.userMapper.updateByPrimaryKeySelective(record);//處理緩存中的數據,先更新數據庫中的數據,再刪除緩存中的數據BoundHashOperations<String, Object, Object> boundHashOps = this.redisTemplate.boundHashOps(KEY_PREFIX2 + username);boundHashOps.delete(username);return true; }

    注:上面的方法還是存在問題的,更好的解決辦法是延時雙刪,當然還有其他辦法有興趣可自行了解

    總結

    以上是生活随笔為你收集整理的乐优商城(11)--用户中心的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。