1. 程式人生 > >企業專案開發--本地快取guava cache(2)

企業專案開發--本地快取guava cache(2)

此文已由作者趙計剛授權網易雲社群釋出。

歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。


AdminCacheKey:

package com.xxx.vo.userManagement;

/**
 * guava cache的key
 */
public class AdminCacheKey {
    private String username;
    private String password;
    private int start;
    private int limit;

    public AdminCacheKey() {
    }

    public AdminCacheKey(String username, String password, int start, int limit) {
        this.username = username;
        this.password = password;
        this.start = start;
        this.limit = limit;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + limit;
        result = prime * result
                + ((password == null) ? 0 : password.hashCode());
        result = prime * result + start;
        result = prime * result
                + ((username == null) ? 0 : username.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        AdminCacheKey other = (AdminCacheKey) obj;
        if (limit != other.limit)
            return false;
        if (password == null) {
            if (other.password != null)
                return false;
        } else if (!password.equals(other.password))
            return false;
        if (start != other.start)
            return false;
        if (username == null) {
            if (other.username != null)
                return false;
        } else if (!username.equals(other.username))
            return false;
        return true;
    }
}

該類是封裝了多個查詢條件的一個VO類。

2.2、ssmm0-userManagement

AdminController:

package com.xxx.web.admin;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.xxx.model.userManagement.Admin;
import com.xxx.service.userManagement.AdminService;
import com.xxx.util.admin.AdminCookieUtil;

/**
 * adminController
 */
@Controller
@RequestMapping("/admin")
public class AdminController {
    
    @Autowired
    private AdminService adminService;
    
    /**
     * 管理員註冊
     */
    @ResponseBody
    @RequestMapping("/register")
    public boolean register(@RequestParam("username") String username,
                            @RequestParam("password") String password){
        Admin admin = new Admin();
        admin.setUsername(username);
        admin.setPassword(password);
        
        boolean isRegisterSuccess = adminService.register(admin);
        
        return isRegisterSuccess;
    }
    
    /**
     * 管理員登入
     */
    @RequestMapping("/login")
    public ModelAndView login(@RequestParam("username") String username,
                              @RequestParam("password") String password,
                              HttpServletResponse response,
                              HttpSession session){
        
        
        Admin admin = adminService.login(username, password);
        
        ModelAndView modelAndView = new ModelAndView();
        if(admin == null){
            modelAndView.addObject("message", "使用者不存在或者密碼錯誤!請重新輸入");
            modelAndView.setViewName("error");
        }else{
            modelAndView.addObject("admin", admin);
            modelAndView.setViewName("userinfo");
            /*
             * 這為什麼不直接傳一個username,而傳了一個admin,
             * 是因為在實際開發中,你傳過去的資訊可能不只是username,還有使用者手機號、地址等等
             */
            //使用cookie
            AdminCookieUtil.addLoginCookie(admin, response);
            //使用session
            //session.setAttribute("adminSession", admin);
        }
        
        return modelAndView;
    }
    
    /*****************************mybatis xml方式解決的問題*******************************/
    /**
     * 根據username或password查詢List<Admin>
     */
    @ResponseBody
    @RequestMapping("/findAdmin")
    public List<Admin> findAdmin(@RequestParam(value="username",required=false) String username,
                                    @RequestParam(value="password",required=false) String password,
                                    @RequestParam("start") int start,
                                    @RequestParam("limit") int limit,
                                    HttpServletRequest request,
                                    HttpSession session){
        Admin admin = AdminCookieUtil.getLoginCookie(request);
        //Admin admin = (Admin) session.getAttribute("adminSession");
        
        if(admin == null){//未登入
            return null;
        }
        System.out.println(admin.toJson());
        List<Admin> adminList = adminService.findAdmin(username, password, start, limit);
        return adminList;
    }
    
    /**
     * 插入一個使用者並返回主鍵
     * 注意:get請求也會自動裝配(即將前臺傳入的username和password傳入admin)
     */
    @ResponseBody
    @RequestMapping("/insert")
    public Admin insertAdminWithBackId(Admin admin){
        return adminService.insertAdminWithBackId(admin);
    }
    /*************************guava cache******************************/
    /**
     * 根據username查詢List<Admin>
     */
    @ResponseBody
    @RequestMapping("/findAdminByUsername")
    public List<Admin> findAdminByUserName(@RequestParam(value="username") String username){
        
        List<Admin> adminList = adminService.findByUsername(username);
        return adminList;
    }
    
    @ResponseBody
    @RequestMapping("/findAdminList")
    public List<Admin> findAdminList(@RequestParam(value="username") String username,
                                         @RequestParam(value="password",required=false) String password,
                                         @RequestParam("start") int start,
                                         @RequestParam("limit") int limit){
        
        List<Admin> adminList = adminService.findAdminList(username, password, start, limit);
        return adminList;
    }
}

將使用到的兩個方法:

  • public List<Admin> findAdminByUserName(String username)

  • public List<Admin> findAdminList(String username, String password, int start, int limit)

3、測試

  • 單元測試:使用springJunit去測就行

  • 整體測試:程式碼寫好之後,注意對程式碼去做測試的方法,先執行相應的controller的方法,然後對查詢出來的部分資料在資料庫中直接進行修改,再執行之前的controller對應的方法。出現兩種結果:

    • 第二次執行與第一次結果相同:快取成功

    • 第二次執行與第一次結果不同:快取不成功

 

4、總結:

  • 常用的幾個API:

    • get(Object key):首先獲取value-->若獲取不到,先快取-->再從快取中去取(以上三步是原子操作),使用該方法優先於使用put

    • getIfPresent(Object key):獲取value,若獲取不到,返回null;若獲取的到,返回value

    • put(Object key, Object value):顯示的新增快取key-value

  • guava cache的get(Object key)的value不能為null(這個可以去看原始碼的註釋),看下邊的程式碼例子:

        LoadingCache<String, List<Admin>> adminListCache = CacheBuilder.newBuilder()
                .expireAfterWrite(20, TimeUnit.MINUTES)// 快取20分鐘
                .maximumSize(1000)// 最多快取1000個物件
                .build(new CacheLoader<String, List<Admin>>() {
                    public List<Admin> load(String username) throws Exception {
                        //1、下邊這樣null的話,不拋異常
                        /*List<Admin> admins = adminDao.getUserByName(username);
                        if(admins==null){
                            return null; 
                        }
                        return admins;*/
                        //2、但是如果這裡查詢出來的結果為null的話,也沒關係
                        //return adminDao.getUserByName(username);
                        //3、如果這裡直接返回null,就會出現com.google.common.cache.CacheLoader$InvalidCacheLoadException
                        return null;
                    }
                });

    注意:該程式碼中的三種null情況,只有第三種會丟擲異常。前兩種不為空的原因是因為,即使admins沒有元素,admins也不會是null,而是[],這應該是mybatis的功勞?!這個是個問題,以後在讀mybatis原始碼的時候,會仔細研究!!!但是實際使用中,我們判斷一個list是否為空,會使用CollectionUtil.isNotEmpty(list)類似於下邊這樣,就會丟擲異常了。

        LoadingCache<String, List<Admin>> adminListCache = CacheBuilder.newBuilder()
                .expireAfterWrite(20, TimeUnit.MINUTES)// 快取20分鐘
                .maximumSize(1000)// 最多快取1000個物件
                .build(new CacheLoader<String, List<Admin>>() {
                    public List<Admin> load(String username) throws Exception {
                        //1、下邊這樣null的話,不拋異常
                        List<Admin> admins = adminDao.getUserByName(username);
                        //System.out.println(admins);//如果admins為空,不會返回null,而是返回[]
                        if(CollectionUtils.isEmpty(admins)){
                            System.out.println(admins+"-->");
                            return null; 
                        }
                        return admins;
                        //2、但是如果這裡查詢出來的結果為null的話,也沒關係
                        //return adminDao.getUserByName(username);
                        //3、如果這裡直接返回null,就會出現com.google.common.cache.CacheLoader$InvalidCacheLoadException
                        //return null;
                    }
                });

    但是,為了在guava cache的使用中不丟擲異常,我們這裡直接使用下邊這句就好了,由mybatis將[]返回就好了。

    return adminDao.getUserByName(username);


免費領取驗證碼、內容安全、簡訊傳送、直播點播體驗包及雲伺服器等套餐

更多網易技術、產品、運營經驗分享請點選


相關文章:
【推薦】 常見的三種撞庫方法
【推薦】 == vs === in Javascript