1. 程式人生 > >(六)基於SSM+Redis+Nginx+FastDFS的部落格網站

(六)基於SSM+Redis+Nginx+FastDFS的部落格網站

上一篇介紹了FastDFS。

這一篇開始介紹redis和FastDFS在本專案中是如何使用的。首先介紹redis

  • Jedis工具類介面
    package com.tdrip.dao;
    
    public interface JedisClient {
    
    	//redis get方法 :get a
    	String get(String key);
    	//redis set方法:set a 10
    	String set(String key, String value);
    	//redis map的get方法
    	String hget(String hkey, String key);
    	//redis map的set方法
    	long hset(String hkey, String key, String value);
    	//redis 自動增長函式,單執行緒,單機情況下可保證執行緒安全
    	long incr(String key);
    	//redis 設定key的有效期
    	long expire(String key, int second);
    	//redis 獲取key的剩餘有效期
    	long ttl(String key);
    	//刪除key
    	long del(String key);
    	//刪除雜湊key
    	long hdel(String hkey, String key);
    	
    }
    

  • Jedis工具類實現,jedisPool通過與spring整合實現注入。
    package com.tdrip.dao.impl;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    import com.tdrip.dao.JedisClient;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    public class JedisClientSingle implements JedisClient{
    	
    	@Autowired
    	private JedisPool jedisPool; 
    	
    	@Override
    	public String get(String key) {
    		Jedis jedis = jedisPool.getResource();
    		String string = jedis.get(key);
    		jedis.close();
    		return string;
    	}
    
    	@Override
    	public String set(String key, String value) {
    		Jedis jedis = jedisPool.getResource();
    		String string = jedis.set(key, value);
    		jedis.close();
    		return string;
    	}
    
    	@Override
    	public String hget(String hkey, String key) {
    		Jedis jedis = jedisPool.getResource();
    		String string = jedis.hget(hkey, key);
    		jedis.close();
    		return string;
    	}
    
    	@Override
    	public long hset(String hkey, String key, String value) {
    		Jedis jedis = jedisPool.getResource();
    		Long result = jedis.hset(hkey, key, value);
    		jedis.close();
    		return result;
    	}
    
    	@Override
    	public long incr(String key) {
    		Jedis jedis = jedisPool.getResource();
    		Long result = jedis.incr(key);
    		jedis.close();
    		return result;
    	}
    
    	@Override
    	public long expire(String key, int second) {
    		Jedis jedis = jedisPool.getResource();
    		Long result = jedis.expire(key, second);
    		jedis.close();
    		return result;
    	}
    
    	@Override
    	public long ttl(String key) {
    		Jedis jedis = jedisPool.getResource();
    		Long result = jedis.ttl(key);
    		jedis.close();
    		return result;
    	}
    
    	@Override
    	public long del(String key) {
    		Jedis jedis = jedisPool.getResource();
    		Long result = jedis.del(key);
    		jedis.close();
    		return result;
    	}
    
    	@Override
    	public long hdel(String hkey, String key) {
    		Jedis jedis = jedisPool.getResource();
    		Long result = jedis.hdel(hkey, key);
    		jedis.close();
    		return result;
    	}
    
    }
    

  •  將需要快取的資料新增到快取後,查詢資料時,首先通過key先訪問快取,若存在該快取的資料,則直接返回快取中的資料,若快取無該資料,則再去資料庫取資料,之後重新新增進快取中。若資料有增刪改的操作時,需要更新快取以確保快取的資料是最新的。

  •  redis的key使用方法:以本專案為例,對所有的文章進行快取時,首先查詢資料庫得到所有的內容List,再將list轉化為Json字串,Key為ALL_CONTENT_REDIS_KEY。也可通過某個字串作為字首+文章唯一的id作為key,比如ALL_CONTENT_REDIS_KEY + id,這樣一個個的進行儲存,用redis的set方法。由於本專案是用於個人的,所以資料量不大,用哪種方法都挺流暢的,如果資料量大的話就得另外考慮了。

  •  下面就貼上專案的文章內容相關的程式碼

  • controller層
    package com.tdrip.controller;
    
    import javax.servlet.http.HttpSession;
    
    import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.tdrip.model.db.ContentModel;
    import com.tdrip.model.db.OperatorModel;
    import com.tdrip.model.util.DataResult;
    import com.tdrip.model.util.ServiceResult;
    import com.tdrip.service.ContentService;
    
    @RestController
    @RequestMapping("/content")
    public class ContentController {
    	
    	@Autowired
    	private ContentService contentService;
    	@Autowired
    	private HttpSession session;
    
    	@RequestMapping(value="/findAll", method = RequestMethod.POST)
    	public DataResult findAll() throws Exception{
    		DataResult dataResult = contentService.findAll();
    		return dataResult;
    	}
    	
    	@RequestMapping(value="/findAudit", method = RequestMethod.POST)
    	public DataResult findAudit() throws Exception{
    	 	OperatorModel model = (OperatorModel) session.getAttribute("admin");
    	 	if (model != null && model.getId().contains("7894F")) {
    	 		DataResult dataResult = contentService.findAutit();	
    	 		return dataResult;
    	 	}
    	 	return DataResult.list();
    	}
    	
    	@RequestMapping(value="/findSelf", method = RequestMethod.POST)
    	public DataResult findByLogin() throws Exception{
    		OperatorModel admin = (OperatorModel) session.getAttribute("admin");
    		if (null != admin && StringUtils.isNotBlank(admin.getId())) {
    			DataResult dataResult = contentService.findByLogin(admin.getId());
    			return dataResult;
    		}
    		return DataResult.list();
    	}
    	
    	@RequestMapping(value = "/findDetailById/{contentId}")
    	public DataResult detail(@PathVariable Long contentId) throws Exception{
    		OperatorModel adminModel = (OperatorModel) session.getAttribute("admin");
    		if (adminModel != null) {
    			DataResult dataResult = contentService.detail(contentId);
    			return dataResult;
    		}
    		return DataResult.list();
    	}
    	
    	@RequestMapping(value = "/add")
    	public ServiceResult add(ContentModel contentModel) throws Exception{
    		OperatorModel adminModel = (OperatorModel) session.getAttribute("admin");
    		if (adminModel != null) {
    			contentModel.setOperatorId(adminModel.getId());
    			contentModel.setUtime(System.currentTimeMillis());
    			contentModel.setCtime(System.currentTimeMillis());
    			ServiceResult serviceResult = contentService.add(contentModel);
    			return serviceResult;
    		}
    		return ServiceResult.Build(-1, "failed");
    	}
    	
    	@RequestMapping(value = "/edit")
    	public ServiceResult edit(ContentModel contentModel) throws Exception{
    		OperatorModel adminModel = (OperatorModel) session.getAttribute("admin");
    		if (adminModel != null) {
    			contentModel.setUtime(System.currentTimeMillis());
    			ServiceResult serviceResult = contentService.edit(contentModel);
    			return serviceResult;
    		}
    		return ServiceResult.Build(-1, "failed");
    	}
    }
    

  • service介面
    package com.tdrip.service;
    
    import com.tdrip.model.db.ContentModel;
    import com.tdrip.model.util.DataResult;
    import com.tdrip.model.util.ServiceResult;
    
    public interface ContentService {
    	public DataResult findAll() throws Exception;
    	public DataResult findAutit() throws Exception;
    	public DataResult findByLogin(String operatorId) throws Exception;
    	public DataResult detail(Long id) throws Exception;
    	public ServiceResult add(ContentModel contentModel) throws Exception;
    	public ServiceResult edit(ContentModel contentModel) throws Exception;
    }
    

  • service實現類
    package com.tdrip.service.impl;
    
    import java.util.List;
    
    import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    import com.tdrip.dao.JedisClient;
    import com.tdrip.mapper.ContentMapper;
    import com.tdrip.model.db.ContentDetailModel;
    import com.tdrip.model.db.ContentModel;
    import com.tdrip.model.util.DataResult;
    import com.tdrip.model.util.ServiceResult;
    import com.tdrip.service.ContentService;
    import com.tdrip.util.IDUtils;
    import com.tdrip.util.JsonUtils;
    
    @Service
    public class ContentServiceImpl implements ContentService {
    
    	@Autowired
    	private ContentMapper contentMapper;
    	@Autowired
    	private JedisClient jedisClient;
    	@Value("${ALL_CONTENT_REDIS_KEY}")
    	private String ALL_CONTENT_REDIS_KEY;
    	@Value("${SELF_CONTENT_REDIS_KEY}")
    	private String SELF_CONTENT_REDIS_KEY;
    	@Value("${CONTENT_DETAIL_REDIS_KEY}")
    	private String CONTENT_DETAIL_REDIS_KEY;
    	
    	/**
    	 * 查詢全部內容
    	 * 1、先從redis快取中查詢,key為ALL_CONTENT_REDIS_KEY
    	 * 2、若redis中有資料,則轉化為javabean直接返回,
    	 * 3、若無則查詢資料庫,並新增到快取中
    	 */
    	@Override
    	public DataResult findAll() throws Exception{
    		
    		//查詢redis
    		String result = jedisClient.get(ALL_CONTENT_REDIS_KEY);
    		if (StringUtils.isNotBlank(result)) {
    			//把字串轉換成list
    			List<ContentModel> resultList = JsonUtils.jsonToList(result, ContentModel.class);
    			return DataResult.list(resultList);
    		}
    
    		//查詢資料庫
    		List<ContentModel> list = contentMapper.selectAll();
    		//將資料轉換成json字串
    		String cacheString = JsonUtils.objectToJson(list);
    		//往快取插入資料
    		jedisClient.set(ALL_CONTENT_REDIS_KEY, cacheString);
    		//設定有效時間
    		jedisClient.expire(ALL_CONTENT_REDIS_KEY, 30*60);
    		
    		return DataResult.list(list);
    	}
    	
    	/**
    	 * 根據當前登入的使用者查詢該使用者的文章
    	 */
    	@Override
    	public DataResult findByLogin(String operatorId) throws Exception{
    		//查詢redis
    		String result = jedisClient.get(SELF_CONTENT_REDIS_KEY + "_" + operatorId);
    		if (StringUtils.isNotBlank(result)) {
    			//把字串轉換成list
    			List<ContentModel> resultList = JsonUtils.jsonToList(result, ContentModel.class);
    			return DataResult.list(resultList);
    		}
    		
    		//查詢資料庫
    		List<ContentModel> list = contentMapper.selectByLogin(operatorId);
    		//將資料轉換成json字串
    		String cacheString = JsonUtils.objectToJson(list);
    		//往快取插入資料
    		jedisClient.set(SELF_CONTENT_REDIS_KEY + "_" + operatorId, cacheString);
    		//設定有效時間30min
    		jedisClient.expire(SELF_CONTENT_REDIS_KEY + "_" + operatorId, 30*60);
    	
    		return DataResult.list(list);
    	}
    
    	/**
    	 * 查詢文章詳細內容
    	 */
    	@Override
    	public DataResult detail(Long id) throws Exception{
    		
    		//查詢redis快取
    		String result = jedisClient.hget(CONTENT_DETAIL_REDIS_KEY, String.valueOf(id));
    		if (StringUtils.isNotBlank(result)) {
    			ContentModel contentModel = JsonUtils.jsonToPojo(result, ContentModel.class);
    			return DataResult.data(contentModel);
    		}
    		
    		//查詢資料庫
    		ContentModel contentModel = contentMapper.selectById(id);
    		if (null != contentModel) {
    			List<ContentDetailModel> list = contentMapper.selectAllDetail(contentModel.getId());
    			if (null != list && list.size() > 0) {
    				contentModel.setContentDetail(list.get(0));
    			}
    			//插入快取
    			//轉換為json字串
    			String cacheString = JsonUtils.objectToJson(contentModel);
    			jedisClient.hset(CONTENT_DETAIL_REDIS_KEY, String.valueOf(contentModel.getId()), cacheString);
    		}
    		return DataResult.data(contentModel);
    	}
    	
    
    	/**
    	 * 新增文章
    	 */
    	@Override
    	public ServiceResult add(ContentModel contentModel) throws Exception{
    		contentModel.setId(IDUtils.genItemId());
    		if (contentMapper.insert(contentModel) > 0) {
    			ContentDetailModel model = contentModel.getContentDetail();
    			if (model != null) {
    				model.setContentId(contentModel.getId());
    				model.setUtime(System.currentTimeMillis());
    				model.setCtime(System.currentTimeMillis());
    				if (contentMapper.insertDetail(model) <= 0) {
    					return ServiceResult.Build(-1, "");
    				}
    			}
    			//使self key失效
    			jedisClient.del(SELF_CONTENT_REDIS_KEY + "_" + contentModel.getOperatorId());
    			//新增資料,使key失效		
    			jedisClient.del(ALL_CONTENT_REDIS_KEY);
    		}
    		return ServiceResult.Ok();
    	}
    
    	/**
    	 * 編輯文章
    	 */
    	@Override
    	public ServiceResult edit(ContentModel contentModel) throws Exception{
    		if (contentMapper.update(contentModel) > 0) {
    			ContentDetailModel model = contentModel.getContentDetail();
    			if (model != null) {
    				model.setContentId(contentModel.getId());
    				model.setUtime(System.currentTimeMillis());
    				//插入資料庫
    				if (contentMapper.updateDetail(model) < 0) {
    					return ServiceResult.Build(-1, "failed");			
    				}
    				//轉換為json字串
    				String cacheString = JsonUtils.objectToJson(contentModel);
    				//修改原有值
    				jedisClient.hset(CONTENT_DETAIL_REDIS_KEY, String.valueOf(contentModel.getId()), cacheString);
    			}
    			//使self key失效
    			jedisClient.del(SELF_CONTENT_REDIS_KEY + "_" + contentModel.getOperatorId());
    			//修改資料,使key失效
    			jedisClient.del(ALL_CONTENT_REDIS_KEY);
    		}
    		return ServiceResult.Ok();
    	}
    
    	/**
    	 * 查詢通過稽核的文章
    	 */
    	@Override
    	public DataResult findAutit() throws Exception{
    		List<ContentModel> list = contentMapper.selectAudit();
    		return DataResult.list(list);
    	}
    }
    

  • mapper介面
    package com.tdrip.mapper;
    
    import java.util.List;
    
    import org.springframework.stereotype.Repository;
    
    import com.tdrip.model.db.ContentDetailModel;
    import com.tdrip.model.db.ContentModel;
    
    @Repository
    public interface ContentMapper {
    	public List<ContentModel> selectAll();
    	public List<ContentModel> selectAudit();
    	public List<ContentModel> selectByLogin(String operatorId);
    	public List<ContentDetailModel> selectAllDetail(Long id);
    	public ContentModel selectById(Long id);
    	public int insert(ContentModel model);
    	public int insertDetail(ContentDetailModel model);
    	public int update(ContentModel model);
    	public int updateStatus(ContentModel model);
    	public int updateDetail(ContentDetailModel model);
    	public int delete(Long id);
    	public int deleteDetail(Long contentId);
    }
    

  • mapper.xml檔案
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    
    <mapper namespace="com.tdrip.mapper.ContentMapper">
    
    	<resultMap type="com.tdrip.model.db.ContentModel" id="ContentResult">
    		<id property="id" column="id" />
    		<result property="title" column="title" />
    		<result property="creater" column="creater" />
    		<result property="operatorId" column="operator_id" />
    		<result property="utime" column="utime" />
    		<result property="ctime" column="ctime" />
    		<result property="picUrl" column="pic_url" />
    		<result property="status" column="status" />
    		<result property="publish" column="publish" />
    		<result property="description" column="description" />
    	</resultMap>
    	
    	<resultMap type="com.tdrip.model.db.ContentDetailModel" id="DetailResult">
    		<id property="id" column="id" />
    		<result property="contentId" column="content_id" />
    		<result property="description" column="description" />
    	</resultMap>
    
    	<sql id="all_column">
    		`id`, `title`, `creater`, `publish`, `operator_id`, `utime`, `ctime`, `pic_url`, `description`, `status`
    	</sql>
    	
    	<sql id="detail_column">
    		`id`, `content_id`, `description`
    	</sql>
    
    	<select id="selectAll" resultMap="ContentResult">
    		<!-- 稽核狀態暫定全部成功1 -->
    		SELECT `id`, `title`, `creater`, `publish`, `operator_id`, `utime`, `ctime`, `pic_url`, `description`
    		FROM content
    		WHERE status=1 AND publish=1
    	</select>
    	
    	<select id="selectByLogin" resultMap="ContentResult">
    		SELECT `id`, `title`, `creater`, `publish`, `operator_id`, `utime`, `ctime`, `pic_url`, `description`, `status`
    		FROM content 
    		WHERE `operator_id` = #{operatorId}
    	</select>
    	
    	<select id="selectById" resultMap="ContentResult">
    		SELECT <include refid="all_column"/> 
    		FROM content
    		WHERE id = #{id}
    	</select>
    	
    	<select id="selectAudit" resultMap="ContentResult">
    		SELECT `title`, `creater`, `utime`, `description`, `status`
    		FROM content
    	</select>
    	
    	<select id="selectAllDetail" resultMap="DetailResult">
    		SELECT <include refid="detail_column"/> 
    		FROM content_detail
    		WHERE content_id = #{id}
    	</select>
    	
    	<insert id="insert">
    		INSERT INTO content(`id`, `title`, utime, ctime, `publish`, pic_url, creater, operator_id, description, `status`)
    		VALUES(#{id},#{title},#{utime},#{ctime},#{publish},#{picUrl},#{creater},#{operatorId},#{description}, #{status})
    	</insert>
    	
    	<insert id="insertDetail" useGeneratedKeys="true" keyProperty="id">
    		INSERT INTO content_detail(`content_id`, utime, ctime, description)
    		VALUES(#{contentId},#{utime},#{ctime},#{description})
    	</insert>
    	
    	<update id="updateDetail">
    		UPDATE content_detail SET `utime`=#{utime}, `description`=#{description}
    		WHERE `content_id`=#{contentId}
    	</update>
    	
    	<update id="update">
    		UPDATE content SET `title`=#{title}, `utime`=#{utime}, `publish`=#{publish}, pic_url=#{picUrl}, description=#{description}, creater=#{creater}
    		WHERE id=#{id}
    	</update>
    	
    	<update id="updateStatus">
    		UPDATE content SET `status`=#{status}
    		WHERE id=#{id}
    	</update>
    	
    	<delete id="delete">
    		DELETE FROM content 
    		WHERE id = #{id}
    	</delete>
    	
    	<delete id="deleteDetail">
    		DELETE FROM content_detail 
    		WHERE content_id = #{contentId}
    	</delete>
    </mapper>