對於程序中一些字典信息、配置信息應該在程序啓動時加載到緩存中,用時先到緩存中取,若是沒有命中,再到數據庫中獲取同時放到緩存中,這樣作能夠減輕數據庫層的壓力。目前暫時先整合ehcache緩存,同時預留了集成redis和memcached的接口。java
先開發兩個最基本的功能,就是註冊和登陸,對於頁面幾乎就是直接用bootstrap的風格,目前沒有過多的設計。redis
在spring boot中整合ehcache仍是很方便的,首先添加依賴:spring
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.2</version> </dependency>
新增ehcache的配置文件,ehcache.xml,即:數據庫
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true"> <diskStore path="java.io.tmpdir" /> <!-- 系統臨時緩存(十分鐘) --> <cache name="SystemTempCache" maxEntriesLocalHeap="0" maxEntriesLocalDisk="10000000" eternal="false" timeToIdleSeconds="0" timeToLiveSeconds="600" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" diskSpoolBufferSizeMB="30" memoryStoreEvictionPolicy="LRU"> </cache> <!-- 系統永久緩存 --> <cache name="SystemEternalCache" maxEntriesLocalHeap="0" maxEntriesLocalDisk="10000000" eternal="true" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" diskSpoolBufferSizeMB="30" memoryStoreEvictionPolicy="LRU"> </cache> </ehcache>
其中設置了兩種緩存類型,一個是臨時緩存,另外一個是永久緩存。bootstrap
此處使用緩存方式不是基於註解的,雖然基於註解的方式也很方便,可是我的以爲仍是本身程序控制緩存好一些。緩存
程序中會將站點的配置信息加載到緩存中,那麼使用方式以下:微信
(1)、首先定義一個緩存接口,本程序中須要用到緩存的,必須實現該接口,即:session
package com.swnote.common.cache; /** * 緩存接口 * * @author lzj * @since 1.0 * @date [2019-04-27] */ public interface ICache<T> { /** * 根據key獲取緩存數據 * * @param key * @return */ public T get(Object key); /** * 存放緩存數據 * * @param key * @param value */ public void put(Object key, T value); /** * 根據key移除內容 * * @param key */ public void remove(Object key); }
(2)、站點配置信息緩存ConfigCache,實現該接口,即:app
package com.swnote.common.cache; import com.swnote.common.domain.Config; import com.swnote.common.service.IConfigService; import com.swnote.common.util.Const; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.List; /** * 緩存配置信息 * 配置信息放到系統永久緩存中,存放形式爲:"_CONFIG" + configId爲key,value爲配置信息對象 * * @author lzj * @since 1.0 * @date [2019-04-27] */ @Slf4j @DependsOn("configService") @Component("configCache") public class ConfigCache implements ICache<Config> { /** * 注入基於Spring提供的Cache接口實例,默認由Ehcache實現 * TODO 之後也能夠是Redis、Memcached提供實現 */ @Autowired private CacheManager cacheManager; @Autowired private IConfigService configService; /** * 系統臨時緩存實例 */ private Cache cache; /** * key的前綴 */ private String keyPrefix = "_CONFIG"; @PostConstruct public void init() { // 獲取系統永久緩存實例 cache = cacheManager.getCache(Const.CACHE_SYSTEM_ETERNAL); log.info("獲取系統永久緩存實例"); log.info("開始加載全部配置信息"); List<Config> configs = configService.list(); if (configs != null && !configs.isEmpty()) { configs.stream().forEach(config -> cache.put(keyPrefix + config.getConfigId(), config)); } log.info("加載完畢全部配置信息"); } @Override public Config get(Object key) { Cache.ValueWrapper valueWrapper = cache.get(keyPrefix + key); if (valueWrapper == null) { // 此時從數據庫從新加載一次 Config config = configService.getById((String) key); if (config == null) { return null; } // 再次放到緩存中 cache.put(keyPrefix + config.getConfigId(), config); return config; } return (Config) valueWrapper.get(); } @Override public void put(Object key, Config value) { cache.put(keyPrefix + key, value); } @Override public void remove(Object key) { cache.evict(keyPrefix + key); } }
註冊頁面效果以下:dom
頁面風格很素,這個暫時先這樣。
主要看一下UserController中處理註冊信息的關鍵代碼,即:
/** * 保存註冊信息 * * @param model * @param request * @return */ @RequestMapping(value = "/auth/signup", method = RequestMethod.POST) @ResponseBody public Result signup(Model model, HttpServletRequest request) { Result result = new Result(); try { // 接收參數 String name = request.getParameter("name"); String email = request.getParameter("email"); String password = request.getParameter("password"); // 簡單校驗 if (StringUtils.isEmpty(name) || StringUtils.isEmpty(email) || StringUtils.isEmpty(password)) { throw new TipException("缺乏必要請求參數"); } if (!StringUtil.isEmail(email)) { throw new TipException("郵箱不符全規範"); } // 校驗用戶名 User tempUser = userService.getByName(name); if (tempUser != null && !StringUtils.isEmpty(tempUser.getUserId())) { throw new TipException("該用戶已經註冊了"); } // 校驗郵箱 tempUser = userService.getByEmail(email); if (tempUser != null && !StringUtils.isEmpty(tempUser.getUserId())) { throw new TipException("該郵箱已經註冊了"); } // 獲取用戶ip String ip = HttpUtil.getIpAddr(request); // 構建用戶信息 User user = new User(); user.setLoginName(name); user.setEmail(email); user.setPassword(StringUtil.md5(password)); user.setCreateIp(ip); // 保存用戶信息 boolean flag = userService.create(user); if (!flag) { throw new TipException("用戶建立失敗"); } result.setCode(Result.CODE_SUCCESS); result.setMsg("用戶建立成功"); } catch (Exception e) { log.error("用戶建立失敗", e); result.setCode(Result.CODE_EXCEPTION); result.setMsg("用戶建立失敗"); } return result; }
在UserService中有一個create方法,即:
@Override public boolean create(User user) { // 獲取當前時間 Date now = new Date(); // 設置主鍵 user.setUserId(IdGenarator.guid()); // 設置未實名認證 user.setRealStatus(User.REAL_STATUS_NO); // 用戶是否須要激活 Config config = configCache.get(Const.CONFIG_USER_ACTIVE); if (config != null && "1".equals(config.getConfigValue())) { // TODO 發送激活郵件信息 // 說明須要激活 user.setIsActive(User.ACTIVE_NO); } else { // 說明不須要激活,默認激活 user.setIsActive(User.ACTIVE_YES); } // 設置啓用帳號狀態 user.setStatus(User.STATUS_YES); // 設置建立時間 user.setCreateTime(now); // 設置關注數爲0 user.setFollows(0); // 設置粉絲數爲0 user.setFans(0); return save(user); }
此處有一個尚未實現的功能,就是發送激活郵件信息,這個功能後面會補上,這裏先處於TODO狀態。
登陸頁面效果以下:
UserController中關鍵的代碼以下:
/** * 處理登陸信息 * * @param request * @return */ @RequestMapping(value = "/auth/login", method = RequestMethod.POST) @ResponseBody public Result login(HttpServletRequest request, HttpSession session) { Result result = new Result(); try { // 接收參數 String name = request.getParameter("name"); String password = request.getParameter("password"); if (StringUtils.isEmpty(name) || StringUtils.isEmpty(password)) { throw new TipException("缺乏必要請求參數"); } // 獲取用戶ip String ip = HttpUtil.getIpAddr(request); User user = userService.verifyUser(name, password, ip); if (user == null) { throw new TipException("用戶名或密碼錯誤"); } // 放置session信息 session.setAttribute(Const.SESSION_USER, user); // TODO 還有一些相關統計信息,後面再加上 result.setCode(Result.CODE_SUCCESS); result.setMsg("登陸成功"); } catch (TipException e) { result.setCode(Result.CODE_EXCEPTION); result.setMsg(e.getMessage()); } catch (Exception e) { log.error("登陸失敗", e); result.setCode(Result.CODE_EXCEPTION); result.setMsg("登陸失敗"); } return result; }
當用戶登陸時,還有一些相關統計信息,這裏因爲其它功能尚未開發完,因此獲取統計信息的代碼後面再加上。
以你最方便的方式關注我:
微信公衆號: