SSM框架學(xué)習(xí)日記(3)——用戶模塊

用戶登錄

在dao層下UserMapper里新增兩個(gè)方法谈山,檢查用戶名和驗(yàn)證登錄

int checkUsername(String username);
User selectLogin(@Param("username") String username,@Param("password") String password);

然后去mappers下UserMapper.xml里寫sql的實(shí)現(xiàn)纹蝴,查詢用select標(biāo)簽,id是在dao層下的方法名,resultType是返回值類型抄淑,parameterType是參數(shù)類型猛遍,標(biāo)簽里寫sql語句馋记,傳入的參數(shù)用#{...}調(diào)用

  <select id="checkUsername" resultType="int" parameterType="string">
    select count(1) from mmall_user
    where username = #{username}
  </select>

  <select id="selectLogin" resultMap="BaseResultMap" parameterType="map">
    select
    <include refid="Base_Column_List" />
    from mmall_user
    where username = #{username}
    and password = #{password}
  </select>

在service層下新建一個(gè)UserService接口類,在子包impl包寫新建UserServiceImpl實(shí)現(xiàn)類懊烤,加上Service注解聲明這個(gè)類是service梯醒,在注入的對(duì)象上加上Autowired注解,自動(dòng)注入腌紧,實(shí)現(xiàn)login和返回響應(yīng)的內(nèi)容

@Service("iUserService")
public class UserServiceImpl implements IUserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public ServerResponse<User> login(String username, String password) {
        int resultCount = userMapper.checkUsername(username);
        if(resultCount == 0){
            return ServerResponse.createByErrorMessage("用戶名不存在");
        }

        //todo 密碼登錄md5

        User user = userMapper.selectLogin(username,password);
        if(user == null){
            return ServerResponse.createByErrorMessage("密碼錯(cuò)誤");
        }
        user.setPassword(StringUtils.EMPTY);
        return ServerResponse.createBySuccess("登錄成功",user);
    }
}

在controller層新建UserController冤馏,Controller注解聲明為Controller。登錄成功把用戶信息放入session寄啼,登出從session刪除逮光。

@Controller
@RequestMapping("/user/")
public class UserController {

    @Autowired
    private IUserService iUserService;
    /**
     * 用戶登錄
     * @param username
     * @param password
     * @param session
     * @return
     */
    @RequestMapping(value = "login.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse<User> login(String username, String password, HttpSession session){
        //service->mybatis->dao
        ServerResponse<User> response = iUserService.login(username,password);
        if(response.isSuccess()){
            session.setAttribute(Const.CURRENT_USER,response.getData());
        }
        return response;
    }

    @RequestMapping(value = "logout.do",method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<String> logout(HttpSession session){
        session.removeAttribute(Const.CURRENT_USER);
        return ServerResponse.createBySuccess();
    }
}

實(shí)現(xiàn)了登錄和登出

用戶注冊(cè)

在UserServiceImpl里新建一個(gè)校驗(yàn)用戶名和email是否存在的方法代箭,傳入兩個(gè)參數(shù),用type區(qū)別傳入的是用戶名還是email

isNoneBlank()和isNotEmpty()的區(qū)別
isNoneBlank(" ")返回的是false涕刚,isNotEmpty(" ")返回的是true

public ServerResponse<String> checkValid(String str,String type){
        if(StringUtils.isNoneBlank(type)){
            if(Const.USERNAME.equals(type)){
                int resultCount = userMapper.checkUsername(str);
                if(resultCount > 0){
                    return ServerResponse.createByErrorMessage("用戶名已存在");
                }
            }
            if(Const.EMAIL.equals(type)){
                int resultCount = userMapper.checkEmail(str);
                if(resultCount > 0){
                    return ServerResponse.createByErrorMessage("email已存在");
                }
            }
        }else{
            return ServerResponse.createByErrorMessage("參數(shù)錯(cuò)誤");
        }
        return ServerResponse.createBySuccessMessage("校驗(yàn)成功");
    }

在UserMapper里配置方法名在UserMapper.xml里實(shí)現(xiàn)sql查詢

int checkEmail(String email);
<select id="checkEmail" resultType="int" parameterType="string">
    select count(1) from mmall_user
    where email = #{email}
 </select>

在寫一個(gè)register方法調(diào)用驗(yàn)證成功后MD5進(jìn)行加密后插入user到數(shù)據(jù)庫

public ServerResponse<String> register(User user){
        ServerResponse validResponse = this.checkValid(user.getUsername(),Const.USERNAME);
        if(!validResponse.isSuccess()){
            return validResponse;
        }
        validResponse = this.checkValid(user.getEmail(),Const.EMAIL);
        if(!validResponse.isSuccess()){
            return validResponse;
        }

        user.setRole(Const.Role.ROLE_CUSTOMER);
        //MD5加密
        user.setPassword(MD5Util.MD5EncodeUtf8(user.getPassword()));

        int resultCount = userMapper.insert(user);
        if(resultCount==0){
            return ServerResponse.createByErrorMessage("注冊(cè)失敗");
        }
        return ServerResponse.createBySuccessMessage("注冊(cè)成功");
    }

MD5工具類
對(duì)外有一個(gè)共有接口MD5EncodeUtf8(),傳入字符串嗡综,加上properties文件里的鹽值,傳給私有方法MD5Encode()然后返回

public class MD5Util {

    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * 返回大寫MD5
     *
     * @param origin
     * @param charsetname
     * @return
     */
    private static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString.toUpperCase();
    }
    public static String MD5EncodeUtf8(String origin) {
        //origin = origin + PropertiesUtil.getProperty("password.salt", "");
        return MD5Encode(origin, "utf-8");
    }
    private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

}

在之前寫的login方法里也要實(shí)現(xiàn)一下md5

....
//todo 密碼登錄md5
String md5password = MD5Util.MD5EncodeUtf8(password);
User user = userMapper.selectLogin(username,md5password);
if(user == null){
    return ServerResponse.createByErrorMessage("密碼錯(cuò)誤");
}
user.setPassword(StringUtils.EMPTY);
    return ServerResponse.createBySuccess("登錄成功",user);
...

最后在controller里調(diào)用一下service的方法杜漠,注冊(cè)接口就完成啦

....
    @RequestMapping(value = "register.do",method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<String> register(User user){
        return iUserService.register(user);
    }

    @RequestMapping(value = "check_valid.do",method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<String> checkValid(String str,String type){
        return iUserService.checkValid(str,type);
    }
}

密碼找回

查找驗(yàn)證找回密碼的問題和答案
在UserServiceImpl類里新增一個(gè)方法

public ServerResponse<String> checkAnswer(String username,String question,String answer){
        int resultCount = userMapper.checkAnswer(username, question, answer);
        if(resultCount>0){
            //答案及問題正確
            String forgetToken = UUID.randomUUID().toString();
            TokenCache.setKey("token_"+username,forgetToken);
            return ServerResponse.createBySuccess(forgetToken);
        }
        return ServerResponse.createByErrorMessage("問題答案錯(cuò)誤");
    }

省略dao層的查詢實(shí)現(xiàn)极景,resultCount>0時(shí),即驗(yàn)證通過時(shí)驾茴,隨機(jī)生成一個(gè)字符串作標(biāo)識(shí)盼樟,然后用GUAVA cache把標(biāo)識(shí)放進(jìn)本地緩存,設(shè)置有效期等配置锈至,新建一個(gè)TokenCache類

public class TokenCache {
    private static Logger logger = LoggerFactory.getLogger(TokenCache.class);

    private static LoadingCache<String,String> localCache = CacheBuilder.newBuilder()
            .initialCapacity(1000)
            .maximumSize(10000)
            .expireAfterAccess(12, TimeUnit.HOURS)
            .build(new CacheLoader<String, String>() {
                //默認(rèn)的數(shù)據(jù)加載實(shí)現(xiàn)晨缴,當(dāng)調(diào)用get取值的時(shí)候,如果key沒有值峡捡,就調(diào)用這個(gè)方法進(jìn)行加載
                @Override
                public String load(String s) throws Exception {
                    return "null";
                }
            });
    public static void setKey(String key,String value){
        localCache.put(key,value);
    }

    public static String getKey(String key){
        String value = null;
        try {
            value = localCache.get(key);
            if("null".equals(value)){
                return null;
            }
            return value;
        }catch (Exception ex){
            logger.error("localCache get error",ex);
        }
        return null;

    }
}

logger是日志輸出击碗,loadingCache是Guava里的本地緩存,.newBuilder()之后.initialCapacity(1000)
初始化它们拙,1000就是緩存的初始化容量稍途,.maximumSize(10000)是最大容量,超過時(shí)使用LRU算法移除緩存項(xiàng)砚婆,.expireAfterAccess(12, TimeUnit.HOURS)設(shè)置了有限期械拍,即12個(gè)小時(shí),然后build装盯。為了避免不必要的exception殊者,把默認(rèn)返回的null,改成字符串null(因?yàn)榕袛鄷r(shí)验夯,null.equals()會(huì)報(bào)錯(cuò))

在UserServiceImpl類里新增一個(gè)方法猖吴,判斷傳進(jìn)來的token和cache中的是否一致,不一致不可以更改密碼挥转,一致就執(zhí)行dao層的update密碼海蔽,

public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){
        if(StringUtils.isBlank(forgetToken)){
            return ServerResponse.createByErrorMessage("參數(shù)錯(cuò)誤,token為空");
        }
        ServerResponse validResponse = this.checkValid(username,Const.USERNAME);
        if(validResponse.isSuccess()){
            //用戶不存在
            return ServerResponse.createByErrorMessage("用戶不存在");
        }

        String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX+username);
        if(StringUtils.isBlank(token)){
            return ServerResponse.createByErrorMessage("token無效");
        }
        if(StringUtils.equals(forgetToken,token)){
            String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
            int rowCount = userMapper.updatePasswordByUsername(username,md5Password);
            if(rowCount>0){
                return ServerResponse.createBySuccessMessage("密碼修改成功");
            }
        }else{
            return  ServerResponse.createByErrorMessage("token錯(cuò)誤");
        }
        return ServerResponse.createByErrorMessage("修改密碼失敗");
    }

然后在controller調(diào)用service層

@RequestMapping(value = "forget_reset_password.do",method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){
        return iUserService.forgetResetPassword(username, passwordNew, forgetToken);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市绑谣,隨后出現(xiàn)的幾起案子党窜,更是在濱河造成了極大的恐慌,老刑警劉巖借宵,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幌衣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)豁护,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門哼凯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人楚里,你說我怎么就攤上這事断部。” “怎么了班缎?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蝴光,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我达址,道長(zhǎng)蔑祟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任沉唠,我火速辦了婚禮疆虚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘右冻。我一直安慰自己装蓬,他們只是感情好著拭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布纱扭。 她就那樣靜靜地躺著,像睡著了一般儡遮。 火紅的嫁衣襯著肌膚如雪乳蛾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天鄙币,我揣著相機(jī)與錄音肃叶,去河邊找鬼。 笑死十嘿,一個(gè)胖子當(dāng)著我的面吹牛因惭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绩衷,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蹦魔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了咳燕?” 一聲冷哼從身側(cè)響起勿决,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎招盲,沒想到半個(gè)月后低缩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡曹货,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年咆繁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了讳推。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡么介,死狀恐怖娜遵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情壤短,我是刑警寧澤设拟,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站久脯,受9級(jí)特大地震影響纳胧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帘撰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一跑慕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摧找,春花似錦核行、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至综苔,卻和暖如春惩系,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背如筛。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工堡牡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杨刨。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓晤柄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親妖胀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芥颈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 去年下半年,公司的食堂因?yàn)橐恍┦虑殛P(guān)閉了做粤,公司的地理位置有些偏浇借,中午休息的時(shí)間又短,周邊零星的幾個(gè)面館小店的食物吃...
    蒼耳的后院閱讀 455評(píng)論 0 1
  • 那麥地多廣闊怕品。好像可以 供我們走很久妇垢。 那綠色多蓬勃,像世上 所有的好,都來到了這里闯估。 我想跟你說很多話灼舍,像小羊 ...
    小花朵先生閱讀 100評(píng)論 0 0
  • 洪都拉斯的景點(diǎn)和博物館一般都會(huì)有三種標(biāo)價(jià):外國人票價(jià)最貴,本國人票價(jià)最便宜涨薪,中美洲國家人票價(jià)居中骑素。我對(duì)哈維說,你看...
    C小姐想太多閱讀 472評(píng)論 0 0
  • 字符串:有下標(biāo)和長(zhǎng)度刚夺,訪問元素也需要便利(用for循環(huán)便利) 聲明一個(gè)字符串 var str='no zuo no...
    _z王箭閱讀 201評(píng)論 0 0