• 基于SpringBoot从零构建博客网站


    对于程序中一些字典信息、配置信息应该在程序启动时加载到缓存中,用时先到缓存中取,如果没有命中,再到数据库中获取同时放到缓存中,这样做可以减轻数据库层的压力。目前暂时先整合ehcache缓存,同时预留了集成redis和memcached的接口。

    先开发两个最基本的功能,就是注册和登录,对于页面几乎就是直接用bootstrap的风格,目前没有过多的设计。

    1、整合ehcache

    在spring boot中整合ehcache还是很方便的,首先添加依赖:

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

    其中设置了两种缓存类型,一个是临时缓存,另一个是永久缓存。

    此处使用缓存方式不是基于注解的,虽然基于注解的方式也很方便,但是个人觉得还是自己程序控制缓存好一些。

    程序中会将站点的配置信息加载到缓存中,那么使用方式如下:

    (1)、首先定义一个缓存接口,本程序中需要用到缓存的,必须实现该接口,即:

    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,实现该接口,即:

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

    2、注册功能

    注册页面效果如下:

    页面风格很素,这个暂时先这样。

    主要看一下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状态。

    3、登录功能

    登录页面效果如下:

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

    当用户登录时,还有一些相关统计信息,这里由于其它功能还没有开发完,所以获取统计信息的代码后面再加上。

    关注我

    以你最方便的方式关注我:
    微信公众号:

  • 相关阅读:
    NDK 在 Android studio如何使用(Android studio NDK)
    懒人习惯之ButterKnife Zelezny
    Android 如何在Eclipse 引入外部纯Java项目(不是打成Jar使用)
    android:ellipsize="end" 失效或者 相关的Bug
    Python 父目录获取
    RecyclerView中实现headerView,footerView功能
    Win7/Win8.1右键菜单技巧:应用程序任意加
    使用android-resource-remover优化资源使用率和lint-result.xml如果导出
    Android Studio 1.1.0版本以上 优化编译
    关于Eclipse如何加入Gradle文件与Android Studio两个平台一起开发,工作目录不发生变化
  • 原文地址:https://www.cnblogs.com/atcloud/p/10831548.html
Copyright © 2020-2023  润新知