ショッピングモール秒殺システムの実現(二)登録機能の実現
34205 ワード
文書ディレクトリデータベース設計 暗号化:2回MD 5 pom.xmlに依存を追加: はloginを記述する.html はjqueryを導入する.js、bootstrap、jquery-validation、layer.js domainで対応するuser を作成パラメータチェック カスタムパラメータ検証器 login部分コード解析 グローバル例外プロセッサ 分散セッション 原理 ログインプロセス: 具体的には を実現する. redisにおけるsetメソッドの実装 addCookie法の実現 完全コード データベース設計
暗号化:MD 5 2回
MD 5ツールクラスの導入、MD 5 Utilの追加
httpは明文で登録されており、安全ではありませんまずクライアントmd 5は、サービス側 に再伝送される.サービス側は、受信後+salt再md 5をデータベースに書き込む(データベースの盗難防止) .
pom.xmlに依存を追加するには:
作成login.html
(コード表示github)
jqueryを導入するjs、bootstrap、jquery-validation、layer.js
(ファイルはgithubを参照)
domainで対応するuserを作成する
パラメータチェツク
スプリングboot-starter-validationの導入
カスタムパラメータ検証
自己定義:
validator:
IsMobileValidator
login部分コード解析
グローバル例外プロセッサ
分散セッション
げんり
実際の実装では,1台のサーバだけではなく,1回目のリクエストが1つ目のサーバに到達し,2回目のリクエストが2つ目のサーバに到達すると,1回目のセッション情報が失われるので,セッション情報をredisに格納する.
ログインプロセス:
ログイン後、to_にジャンプリストページがジャンプするときにパラメータを持ってきて、クッキー(またはrequestのパラメータ)を使って、to_リストでは、クッキーのパラメータを取り出し、パラメータを介してredisからuserがこのuserを示す貨物インタフェースを取得します.
ユーザ情報をredisに格納するにはtoken一意の識別が必要である(ログインに成功した後、このユーザにsessionIDのようなものを生成し、このユーザを表示し、cookieに書いてクライアントに伝え、クライアントはその後のアクセスでcookieでtokenを伝え、サービス側はこのtokenを取得した後、このtokenでユーザ対応のsession情報を取得する)
具体的な実装
redisにおけるsetメソッドの実装
addCookieメソッドの実装
クッキーに書く:token=>cookieこのtokenがどのユーザに対応しているかを示すため、このユーザ情報をredisに書く(サードパーティキャッシュ)ことで、tokenを知るだけでユーザ情報が得られる
完全なコード
上のloginと最後のaddCookieの部分です
CREATE TABLE miaosha_user (
`id` bigint(20) NOT NULL COMMENT ' ID, ',
`nickname` varchar(255) NOT NULL,
`password` varchar(32) DEFAULT NULL COMMENT 'MD5(MD5(pass + salt) + salt)',
`salt` varchar(10) DEFAULT NULL,
`head` varchar(128) DEFAULT NULL COMMENT ' , ID',
`register_date` datetime DEFAULT NULL COMMENT ' ',
`last_login_date` datetime DEFAULT NULL COMMENT ' ',
`login_count` int(11) DEFAULT '0' COMMENT ' ',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
暗号化:MD 5 2回
MD 5ツールクラスの導入、MD 5 Utilの追加
httpは明文で登録されており、安全ではありません
pom.xmlに依存を追加するには:
<dependency>
<groupId>commons-codecgroupId>
<artifactId>commons-codecartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.6version>
dependency>
作成login.html
(コード表示github)
jqueryを導入するjs、bootstrap、jquery-validation、layer.js
(ファイルはgithubを参照)
domainで対応するuserを作成する
public class MiaoshaUser {
private Long id;
private String nickname;
private String password;
private String salt;
private String head;
private Date registerDate;
private Date lastLoginDate;
private Integer loginCount;
}
パラメータチェツク
スプリングboot-starter-validationの導入
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
dependency>
カスタムパラメータ検証
自己定義:
validator:
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = IsMobileValidator.class)// ismobilexxx
public @interface IsMobile {
String message() default " ";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
boolean required() default true; //
}
public class IsMobileValidator implements ConstraintValidator<IsMobile, String>{
}
IsMobileValidator
public class IsMobileValidator extends ConstraintValidator<>(){
private boolean required = false;
public void initialize(IsMobile constraintAnnotation){
required =
}
public boolean isValid(){
if(required){
return ValidatorUtil.isMobile
}
else{
if(StringUtils.isEmpty(value)){
return true;
}
else {
return ValidatorUtil.isMobile(value);
}
}
}
}
login部分コード解析
public boolean login(HttpServletResponse response,LoginVo loginVo) {
if(loginVo == null) {
throw new GlobalException(CodeMsg.SERVER_ERROR);
}
String mobile = loginVo.getMobile();
String formpass = loginVo.getPassword();
MiaoshaUser user = getById(Long.parseLong(mobile));//
if(user == null) {
throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
}
//
String dbPass = user.getPassword();//
String saltDB = user.getSalt();// salt
String calcPass = MD5Util.formPass2DBPass(formpass, saltDB);// salt calc
if(!calcPass.equals(dbPass)) {//
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
}
グローバル例外プロセッサ
@ControllerAdvice
@ResponseBody
@ExceptionHandler(value=Excption.class)
public Result<String> excptionHandler(HttpServletRequest request ,Exeption e){
if(e instanceof BindException){
BindException ex = (BindException)e;
List<ObjectError> errors = ex.getAllErrors();
return Result.error(CodeMsg.BIND_EORROR.fillArgs());
}
}
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(value=Exception.class)
public Result<String> allExceptionHandler(HttpServletRequest request, Exception exception) throws Exception{
}
}
分散セッション
げんり
実際の実装では,1台のサーバだけではなく,1回目のリクエストが1つ目のサーバに到達し,2回目のリクエストが2つ目のサーバに到達すると,1回目のセッション情報が失われるので,セッション情報をredisに格納する.
ログインプロセス:
ログイン後、to_にジャンプリストページがジャンプするときにパラメータを持ってきて、クッキー(またはrequestのパラメータ)を使って、to_リストでは、クッキーのパラメータを取り出し、パラメータを介してredisからuserがこのuserを示す貨物インタフェースを取得します.
ユーザ情報をredisに格納するにはtoken一意の識別が必要である(ログインに成功した後、このユーザにsessionIDのようなものを生成し、このユーザを表示し、cookieに書いてクライアントに伝え、クライアントはその後のアクセスでcookieでtokenを伝え、サービス側はこのtokenを取得した後、このtokenでユーザ対応のsession情報を取得する)
具体的な実装
redisにおけるsetメソッドの実装
//
// : +key+value
public <T> boolean set(KeyPrefix prefix, String key, T value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String str = beanToString(value);
if(str == null || str.length() <= 0) {
return false;
}
// key
String realKey = prefix.getPrefix() + key;
int seconds = prefix.expireSeconds();
if(seconds <= 0) {
jedis.set(realKey, str);
}else {
jedis.setex(realKey, seconds, str);
}
return true;
}finally {
returnToPool(jedis);
}
}
addCookieメソッドの実装
クッキーに書く:token=>cookieこのtokenがどのユーザに対応しているかを示すため、このユーザ情報をredisに書く(サードパーティキャッシュ)ことで、tokenを知るだけでユーザ情報が得られる
// cookie response ,redis
private void addCookie(HttpServletResponse response, String token, MiaoshaUser user) {
//1. redis
// set : +key+value
//MiaoshaUserKey.token , MiaoshaUserKey
redisService.set(MiaoshaUserKey.token, token, user);
//2. cookie response
Cookie cookie = new Cookie(COOKIE_NAME_TOKEN, token);
//
cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
cookie.setPath("/");
response.addCookie(cookie);
}
完全なコード
上のloginと最後のaddCookieの部分です
public boolean login(HttpServletResponse response,LoginVo loginVo) {
if(loginVo == null) {
throw new GlobalException(CodeMsg.SERVER_ERROR);
}
String mobile = loginVo.getMobile();
String formpass = loginVo.getPassword();
MiaoshaUser user = getById(Long.parseLong(mobile));//
if(user == null) {
throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
}
//
String dbPass = user.getPassword();//
String saltDB = user.getSalt();// salt
String calcPass = MD5Util.formPass2DBPass(formpass, saltDB);// salt calc
if(!calcPass.equals(dbPass)) {//
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
// token( immutable universally unique identifier )
String token = UUIDUtil.uuid();
addCookie(response, token, user);
return true;
}