1. 程式人生 > >基於SpringBoot從零構建部落格網站 - 新增建立、修改、刪除專欄功能

基於SpringBoot從零構建部落格網站 - 新增建立、修改、刪除專欄功能

守望部落格是支援建立專欄的功能,即可以將一系列相關的文章歸檔到專欄中,方便使用者管理和查閱文章。這裡主要講解專欄的建立、修改和刪除功能,至於專欄還涉及其它的功能,例如關注專欄等後續會穿插著介紹。

1、建立專欄

接收和處理專欄相關功能的操作的方法會放在GroupController類中,首先建立專欄的頁面為:

這裡有兩個地方需要特別說明:

第一這個分類資料,此處分類資料正是本部落格網站的分類資料,這個分類資料是系統初始化時加入的,這個初始化的功能後續會加入,目前此處就是提前將資料先寫入到資料庫中,例如本部落格作為技術類部落格,則分類有:前端、架構、區塊鏈、雲端計算等。

然後這個分類資訊資料一般初始化後,就不會有修改,則這個資料是放入快取中,即,CategoryCache:

/**
 * 快取分類資訊
 * 分類資訊放到系統永久快取中,存放形式為:"_CATEGORY" + categoryId為key,value為分類資訊物件
 *
 * @author lzj
 * @since 1.0
 * @date [2019-07-22]
 */
@Slf4j
@DependsOn("categoryService")
@Component("categoryCache")
public class CategoryCache implements ICache<List<Category>> {

    /**
     * 注入基於Spring提供的Cache介面例項,預設由Ehcache實現
     * TODO 以後也可以是Redis、Memcached提供實現
     */
    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private ICategoryService categoryService;

    /**
     * 快取例項
     */
    private Cache cache;

    /**
     * key的字首
     */
    private String keyPrefix = "_CATEGORY";

    /**
     * 分類資訊根節點ID
     */
    public static final String ROOT_CATEGORY_ID = "0";

    @PostConstruct
    public void init() {
        // 獲取系統永久快取例項
        cache = cacheManager.getCache(Const.CACHE_SYSTEM_ETERNAL);
        log.info("獲取系統永久快取例項");

        log.debug("開始載入父分類資訊");
        List<Category> categorys = categoryService.getByParentId(ROOT_CATEGORY_ID);
        if (categorys != null && !categorys.isEmpty()) {
            put(keyPrefix + ROOT_CATEGORY_ID, categorys);
        }
        log.debug("載入完畢父分類資訊");
    }

    @Override
    public List<Category> get(Object key) {
        Cache.ValueWrapper valueWrapper = cache.get(keyPrefix + key);
        if (valueWrapper == null) {
            // 從資料庫重新載入一次
            List<Category> categorys = categoryService.getByParentId((String) key);
            if (categorys == null) {
                return null;
            }

            // 再次放到快取中
            put(key, categorys);

            return categorys;
        }
        return (List<Category>) valueWrapper.get();
    }

    @Override
    public void put(Object key, List<Category> value) {
        cache.put(keyPrefix + key, value);
    }

    @Override
    public void remove(Object key) {
        cache.evict(keyPrefix + key);
    }
}

第二需要說明的是,此處的上傳控制是用的webuploader,利用webuploader處理的上傳檔案的話,需要按如下方式初始化:

$(function() {
    var _list = $('#fileList');
    var ratio = window.devicePixelRatio || 1;
    var thumbnailWidth = 100 * ratio;
    var thumbnailHeight = 100 * ratio;

    // 初始化Web Uploader
    var uploader = WebUploader.create({

        // 選完檔案後,是否自動上傳。
        auto: true,

        // swf檔案路徑
        swf: '${rc.contextPath}/static/plugins/webuploader/Uploader.swf',

        // 檔案接收服務端。
        server: '${rc.contextPath}/upload',

        // 選擇檔案的按鈕。可選。
        // 內部根據當前執行是建立,可能是input元素,也可能是flash.
        pick: '#filePicker',

        fileVal: "_uploadFile",

        formData: {
            _distId:'_distId',
            _distType:'_groupLogo',
        },

        // 只允許選擇圖片檔案。
        accept: {
            title: 'Images',
            extensions: 'gif,jpg,jpeg,png',
            mimeTypes: 'image/*'
        },

        fileNumLimit: 1,
        fileSizeLimit: 2 * 1024 * 1024,    // 2 M
        fileSingleSizeLimit: 2 * 1024 * 1024    // 2 M
    });

    // 當有檔案新增進來的時候
    uploader.on( 'fileQueued', function( file ) {
        var li = $(
            '<div id="' + file.id + '" class="file-item thumbnail text-center">' +
            '<img>' +
            // '<div class="info">' + file.name + '</div>' +
            '</div>'
            ),
            img = li.find('img');


        // _list為容器jQuery例項
        _list.append( li );

        // 建立縮圖
        // 如果為非圖片檔案,可以不用呼叫此方法。
        // thumbnailWidth x thumbnailHeight 為 100 x 100
        uploader.makeThumb( file, function( error, src ) {
            if ( error ) {
                img.replaceWith('<span>不能預覽</span>');
                return;
            }

            img.attr( 'src', src );
        }, thumbnailWidth, thumbnailHeight );
    });

    // 檔案上傳過程中建立進度條實時顯示。
    uploader.on( 'uploadProgress', function( file, percentage ) {
    });

    // 檔案上傳成功,給item新增成功class, 用樣式標記上傳成功。
    uploader.on( 'uploadSuccess', function(file, response) {
        $( '#'+file.id ).addClass('upload-state-done');
        $( '#'+file.id ).append('<a class="del" href="javascript:void(0);">刪除</a>' )
        $("#logo").val(response.url);
    });

    // 檔案上傳失敗,顯示上傳出錯。
    uploader.on( 'uploadError', function( file ) {
        var li = $( '#'+file.id ),
            error = li.find('div.error');

        // 避免重複建立
        if ( !error.length ) {
            error = $('<div class="error"></div>').appendTo( li );
        }

        error.text('上傳失敗');
    });

    // 完成上傳完了,成功或者失敗,先刪除進度條。
    uploader.on( 'uploadComplete', function( file ) {
    });

    // 執行刪除方法
    _list.on('click', '.del', function () {
        var Id = $(this).parent().attr('id');
        //刪除該圖片
        uploader.removeFile(uploader.getFile(Id, true));
        $(this).parent().remove();
        $("#logo").val("");
    });
});

這裡後臺需要處理專欄的Logo圖片的資訊,根據上一章節的方式處理,即有UploadGroupLogoHandler類,如:

/**
 * 上傳專欄Logo處理類
 *
 * @author lzj
 * @since 1.0
 * @date [2019-07-23]
 */
@Slf4j
@Component("_groupLogo")
public class UploadGroupLogoHandler implements IUploadHandler {

    @Resource(name = "configCache")
    private ICache<Config> configCache;

    @Override
    public Object upload(MultipartFile file, String distType, String userId) throws Exception {
        Map<String, Object> result = new HashMap<String, Object>();
        try {
            // 獲取圖片的原始名稱
            String originalName = file.getOriginalFilename();

            // 判斷圖片的型別
            if (!(originalName.endsWith(".jpg") || originalName.endsWith(".JPG") || originalName.endsWith(".png") || originalName.endsWith(".PNG") || originalName.endsWith(".gif") || originalName.endsWith(".GIF") || originalName.endsWith(".jpeg") || originalName.endsWith(".JPEG"))) {
                throw new TipException("您上傳的圖片型別有誤,請上傳格式為jpg、png或gif");
            }

            // 獲取圖片的大小
            long fileSize = file.getSize();

            // 圖片大小不能超過2M, 2M = 2 * 1024 * 1024B = 2097152B
            if (fileSize > 2097152L) {
                throw new TipException("您上傳的圖片超過2M");
            }

            Config config = configCache.get(Config.CONFIG_IMG_GROUP_LOGO_PATH);
            // 儲存頭像的根目錄
            String basePath = config.getConfigValue();
            if (!(basePath.endsWith("/") || basePath.endsWith("\\"))) {
                basePath += "/";
            }

            // 根據當前時間構建yyyyMM的資料夾,建立到月的資料夾
            String dateDirName = DateUtil.date2Str(new Date(), DateUtil.YEAR_MONTH_FORMAT);
            basePath += dateDirName;

            File imageDir = new File(basePath);
            if (!imageDir.exists()) {
                imageDir.mkdirs();
            }

            String fileNewName = IdGenarator.guid() + originalName.substring(originalName.lastIndexOf("."));
            FileUtil.copy(file.getInputStream(), new FileOutputStream(new File(imageDir, fileNewName)));

            result.put("url", dateDirName + "/" + fileNewName);
            result.put("msg", "上傳成功");
        } catch (TipException e) {
            result.put("url", "");
            result.put("msg", e.getMessage());
        } catch (Exception e) {
            log.error("上傳失敗", e);
            result.put("url", "");
            result.put("msg", "上傳失敗");
        }
        return result;
    }

    @Override
    public void download(String fileId, HttpServletResponse response) throws Exception {
    }

    @Override
    public Object list(String distType, String userId) throws Exception {
        return null;
    }
}

最後建立專欄的核心程式碼如下:

/**
 * 建立專欄
 *
 * @param request
 * @param session
 * @return
 */
@RequestMapping(value = "/user/group/add", method = RequestMethod.POST)
@ResponseBody
public Result add(HttpServletRequest request, HttpSession session) {
    Result result = new Result();
    try {
        // 接收引數
        String categoryId = request.getParameter("categoryId");
        String name = request.getParameter("name");
        String logo = request.getParameter("logo");
        String introduce = request.getParameter("introduce");

        // 校驗引數
        if (StringUtils.isEmpty(categoryId) || StringUtils.isEmpty(name) || StringUtils.isEmpty(logo) || StringUtils.isEmpty(introduce)) {
            throw new TipException("缺少必要引數");
        }

        // 獲取登入資訊
        User tempUser = (User) session.getAttribute(Const.SESSION_USER);
        String userId = tempUser.getUserId();

        // 構建專欄物件
        Group group = new Group();
        group.setGroupId(IdGenarator.longIdStr());
        group.setName(name);
        group.setLogo(logo);
        group.setIntroduce(introduce);
        group.setCategoryId(categoryId);
        group.setCreator(userId);
        group.setCreateTime(new Date());
        // 從系統配置項獲取專欄是否稽核
        Config config = configCache.get(Config.CONFIG_GROUP_AUDIT);
        if (config != null && "1".equals(config.getConfigValue())) {
            // 需要稽核
            group.setStatus(Group.STATUS_NO);
        } else {
            // 不需要稽核
            group.setStatus(Group.STATUS_SUCCESS);
        }

        // 儲存專欄資訊
        boolean flag = groupService.save(group);
        if (!flag) {
            throw new TipException("建立專欄失敗");
        }

        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;
}

2、修改專欄

有了前面新增專欄的基礎,其實修改專欄的功能就相對簡單很多了,此處只列出處理修改的核心程式碼即可,如:

/**
 * 修改專欄
 *
 * @param groupId
 * @param request
 * @param session
 * @return
 */
@RequestMapping(value = "/user/group/edit/{groupId}", method = RequestMethod.POST)
@ResponseBody
public Result edit(@PathVariable("groupId") String groupId, HttpServletRequest request, HttpSession session) {
    Result result = new Result();
    try {
        // 根據id獲取專欄資訊
        Group group = groupService.getById(groupId);
        if (group == null || StringUtils.isEmpty(group.getGroupId())) {
            log.error("groupId: " + groupId + ": 該專欄不存在");
            throw new TipException("該專欄不存在");
        }

        // 獲取使用者資訊
        User tempUser = (User) session.getAttribute(Const.SESSION_USER);
        String userId = tempUser.getUserId();
        if (!userId.equals(group.getCreator())) {
            log.error("userId: " + userId + "修改別人的groupId: " + groupId);
            throw new TipException("不能修改別人的專欄");
        }

        // 接收引數
        String categoryId = request.getParameter("categoryId");
        String name = request.getParameter("name");
        String introduce = request.getParameter("introduce");
        String logo = request.getParameter("logo");

        // 校驗引數
        if (StringUtils.isEmpty(categoryId) || StringUtils.isEmpty(name) || StringUtils.isEmpty(introduce)) {
            throw new TipException("缺少必要引數");
        }

        group.setCategoryId(categoryId);
        group.setName(name);
        group.setIntroduce(introduce);
        if (!StringUtils.isEmpty(logo)) {
            group.setLogo(logo);
        }
        group.setUpdateTime(new Date());

        // 修改
        boolean flag = groupService.updateById(group);
        if (!flag) {
            throw new TipException("修改專欄失敗");
        }

        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;
}

3、刪除專欄

刪除專欄功能是很簡單的,但是需要考慮到,刪除專欄後,需要處理其它與之關聯的資料資訊,此處由於其它模組還沒有完成,所以先將加一個TODO,後續會再處理。那刪除專欄的核心程式碼如下:

/**
 * 根據ID刪除專欄
 *
 * @param groupId
 * @param session
 * @return
 */
@RequestMapping(value = "/user/group/delete/{groupId}", method = RequestMethod.GET)
@ResponseBody
public Result delete(@PathVariable("groupId") String groupId, HttpSession session) {
    Result result = new Result();
    try {
        // 根據id獲取專欄資訊
        Group group = groupService.getById(groupId);
        if (group == null || StringUtils.isEmpty(group.getGroupId())) {
            log.error("groupId: " + groupId + ": 該專欄不存在");
            throw new TipException("該專欄不存在");
        }

        // 獲取使用者資訊
        User tempUser = (User) session.getAttribute(Const.SESSION_USER);
        String userId = tempUser.getUserId();
        if (!userId.equals(group.getCreator())) {
            log.error("userId: " + userId + "刪除別人的groupId: " + groupId);
            throw new TipException("不能刪除別人的專欄");
        }

        // 刪除
        boolean flag = groupService.removeById(groupId);
        if (!flag) {
            throw new TipException("刪除專欄失敗");
        }

        // 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;
}

關注我

以你最方便的方式關注我:
微信公眾號:

相關推薦

基於SpringBoot構建部落網站 - 新增建立修改刪除專欄功能

守望部落格是支援建立專欄的功能,即可以將一系列相關的文章歸檔到專欄中,方便使用者管理和查閱文章。這裡主要講解專欄的建立、修改和刪除功能,至於專欄還涉及其它的功能,例如關注專欄等後續會穿插著介紹。 1、建立專欄 接收和處理專欄相關功能的操作的方法會放在GroupController類中,首先建立專欄的頁面為:

基於SpringBoot構建部落網站 - 整合ehcache和開發註冊登入功能

對於程式中一些字典資訊、配置資訊應該在程式啟動時載入到快取中,用時先到快取中取,如果沒有命中,再到資料庫中獲取同時放到快取中,這樣做可以減輕資料庫層的壓力。目前暫時先整合ehcache快取,同時預留了整合redis和memcached的介面。 先開發兩個最基本的功能,就是註冊和登入,對於頁面幾乎就是直接用bo

基於SpringBoot構建部落網站 - 開發設定主頁標識和修改個人資訊功能

由於守望部落格系統中支援由使用者自己設定個人主頁的URL的後半段,所以必須要使用者設定該標識的功能,而且是使用者註冊登入之後自動彈出的頁面,如果使用者沒有設定該標識,其它的操作是不能夠操作的,同時要求主頁標識只能設定一次。 使用者註冊時只是填寫了簡單的登入資訊,所以使用者登入後,可以設定個人詳細的資訊,也即修

基於SpringBoot構建部落網站 - 設計可擴充套件上傳模組和開發修改頭像密碼功能

上傳模組在web開發中是很常見的功能也是很重要的功能,在web應用中需要上傳的可以是圖片、pdf、壓縮包等其它型別的檔案,同時對於圖片可能需要回顯,對於其它檔案要能夠支援下載等。在守望部落格系統中對於上傳模組進行統一管理,同時對於上傳不同的型別檔案,留有自定義實現機制的介面,也即可擴充套件。 基於上傳模組機制

基於SpringBoot構建部落網站 - 整合editor.md開發釋出文章功能

釋出文章功能裡面最重要的就是需要整合富文字編輯器,目前富文字編輯器有很多,例如ueditor,CKEditor、editor.md等。這裡守望部落格裡面是整合的editor.md,因為editor.md是markdown格式,目前markdown由於簡潔好用,在各種雲筆記、github等中得到了廣泛使用。 1

基於SpringBoot構建博客網站 - 確定需求和表結構

簡單 order itl long tab 轉載 href 保存文件 存儲 要確定一個系統的需求,首先需要明確該系統的用戶有哪些,然後針對每一類用戶,確定其需求。對於博客網站來說,用戶有3大類,分別是: 作者,也即是註冊用戶 遊客,也即非註冊用戶 管理員,網站維護人員

SpringBoot搭建部落網站(可提供原始碼)

文字不夠,圖片來湊。 前言 為什麼想要搭建這個部落格? 我還記得,在大二寒假的某天,同往常一樣的在家解決這某個bug,不停地問度娘,很巧的碰到了一個同行在他的部落格中完美的記錄了我的bug的解決方案,隨後我又看了看他寫的其他部落格文章,覺得都非常的不錯,並

開發部落-讓Flask-admin支援markdown編輯器(一)

前言 flask-admin 算是一個很不錯的 flask 後臺管理了,用它來做部落格系統的管理後端再合適不過了,節約時間成本,避免重複造輪子,但是作為一個程式設計師,寫文章怎麼可以沒有 markdown 呢? 現在讓我們嘗試一下讓 flask-admin 支援 markdown 吧. 實踐 Flask

基於雲端儲存的個人部落網站的設計與實現

**基於雲端儲存的個人部落格網站的設計與實現** 基於雲端儲存的個人部落格網站的設計與實現mysql資料庫建立語句 基於雲端儲存的個人部落格網站的設計與實現oracle資料庫建立語句 基於雲端儲存的個人部落格網站的設計與實現sqlserver資料庫建立語句 基於雲端

使用python在wordpress部落網站新增新文章示例

Wodrepress是最近很火的一個部落格平臺,利用它可以快速搭建各種網站。下面我是利用xmlrpc程式設計介面在wordpress新增文章的示例程式碼: import datetime, xmlrpclib wp_url = "http://www.example.co

基於Bmob開始寫一個部落小程式

實現以下技能點 1、整合Bmob小程式SDK作為資料儲存 2、wemark解析markdown文字 3、列表頁佈局與上拉無限載入 實現的效果 一、建立Bmob應用 進入Bmob官網:http://bmob.cn/,註冊一個賬號,免費的賬號可以建立8個子應用,每個應用單表列數是20列,如要購買付費,可以分

使用LAMP建立基於wordpress的個部落網站

參考: http://blog.csdn.net/ck_boss/article/details/27866117 一、mysql配置 1、安裝mysql yum install mysql-server  CentOS中已經預設安裝,此步驟忽略。 2、啟動mysql

到一快速搭建個人部落網站(域名備案 + https免費證書)(一)

## 前言        為什麼選擇搭建個人部落格?一方面是各個平臺經常下架原創文章,另一個方面是為了熟悉整個建站流程。        通過搭建個人部落格,我們可以自由的

0開始使用python flask編寫部落網站(2)

好了上一篇文章中搭建好了完整的框架,以及可以訪問一個“hello world”頁面了。現在繼續完善我們的部落格程式。 1.如法炮製,繼續完善error和admin的路由。 首先寫把404和500的網頁寫好放到templates/errors中。然後在error的資料夾中新建handlers.py 檔案,在

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

 本篇介紹FastDFS,無需整合spring即可使用,前端上傳圖片到控制層,控制層呼叫fastDFS工具類實現上傳,上傳成功返回檔案地址到前端。 配置檔案為fast_client.conf,fastDFS要求使用的檔名和屬性名,要一致。 tracker_server =

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

  這篇部落格介紹的是自我用了SSM(spring、SpringMVC和Mybatis)後,基於一個前端模板做的一個網站。由於自己比較喜歡做分散式架構的網站,所以就基於自己現有所學的技術實現某些功能,當然肯定有很多可以改進的地方。基本框架用的是SSM,資料庫用的是MYSQL,快取用

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

上一篇主要介紹了SSM整合以及測試。 這一篇主要介紹登入模組,登入模組用到了過濾器,配置過濾器時需要在web.xml裡面進行配置,相關配置已經在第二篇的web.xml有註明。  本篇涉及的類有:控制層的LoginController、過濾器CheckLoginFilte

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

 上一篇介紹了redis的相關使用,這一篇介紹本專案使用的圖片儲存時用到的技術——FastDFS。專案使用時參考的是傳智播客裡的FastDFS的使用教程。由於只有文件沒有地址,所以就直接黏貼過來,若有版權問題請告知,謝謝。 1 課程目標

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

上一篇介紹了FastDFS。 這一篇開始介紹redis和FastDFS在本專案中是如何使用的。首先介紹redis Jedis工具類介面 package com.tdrip.dao; public interface JedisClient { //redis get方法 :

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

 Redis是用C語言開發的一個開源的高效能鍵值對(key-value)資料庫。它通過提供多種鍵值資料型別來適應不同場景下的儲存需求,目前為止Redis支援的鍵值資料型別如字串型別、雜湊型別、列表型別、集合型別、有序集合型別。 菜鳥教程裡有基本的使用命令:點選開啟連結