2018-07-02 尔雅平台

2021-07-13
时隔多日,再回首看缓存又有了不同的感悟
缓存应该本地缓存+redis分布式缓存搭建多级缓存
原因:无论如何本地缓存是最快的,之后才是redis,最后是不用缓存。
存在问题:缓存是存在上限的,如何在有限的空间内保证高速缓存?将高频次的缓存存在本地,采用一种淘汰策略保证存储数据既不会溢出又保证高效。如果本地缓存没有命中,则从分布式缓存中获取。如果分布式缓存依然没有获取则从数据库读取,获取到有效数据后存入本地和分布式缓存中,通过过期时间及淘汰策略保证缓存的高速有效。

最近试用spring boot cache 时发现如果项目中引入redis,会默认试用redis缓存,但是可以通过修改cacheType为Simple改为本地缓存
在使用本地缓存时发现一个小坑,不要修改获取的缓存数据,因为会直接修改缓存值,造成的结果可能是一个数值的不停修改;

2019-05-05 虽然已经换公司了,但是对缓存的理解还是写在这里
缓存:多用redis, 少用springboot自带的,因为redis可以分布式调用,扩展性比较好
java缓存原理:以一个获取机构logo的方法为例

 //创建一个map作为缓存
    private Map iconMap = new HashMap<>();
    public String getOrgLogo(String orgId) {
        if (StringUtils.isEmpty(orgId)) {
            return "";
        }
        //从缓存中读取
        String icon = iconMap.get(orgId);
        if (StringUtils.isEmpty(icon)){
            //没读到,从数据库获取
            OrgDO orgDO = orgDao.get(orgId);
            if (orgDO != null && !StringUtils.isEmpty(orgDO.getLogo())) {
                //将读取的数据加入缓存
                iconMap.put(orgId,orgDO.getLogo());
                return orgDO.getLogo();
            } else {
                return "";
            }
        }else {
            return icon;
        }
    }

需要清除缓存只需要一个iconMap.clear()即可
2018.10.17 由于网站用户访问量过大,开始优化性能

添加缓存

1.springboot 开启缓存: 在 @SpringBootApplication下添加@EnableCaching
2.在service 上添加@Cacheable("serviceName")
缓存机制:参数默认为缓存名,key为service方法中的参数。所以涉及分页问题时,需要在方法中传入当前页面的参数

清除缓存

service 上添加@CacheEvict(value = {"serviceName1","serviceName2","serviceName3"},allEntries = true)
如果修改数据,由于有缓存的存在,数据不会刷新,所以需要在修改数据的方法上添加清除缓存的注解;
参数value为需要清除的缓存名,allEntries表示将方法下的所有缓存全部清理

使用感受:添加缓存后,如果参数一致,则不进行service内的操作,直接返回上次的结果,项目的性能疯狂提升

使用静态资源服务器

将封面图等静态文件存入静态服务器上
之后通过http的方式来加载图片

存在问题:由于静态服务器上有缓存,导致重名文件无法正常加载。

自己完整开发的项目;感谢大神的帮助。。

项目搭建:

数据库设计

通过设计图简单总结了项目中会出现类基本来说全是类别与资源,二者之间是多对多的关系所以建立一个中间表就可以开始了
之后大神提点:如果可能,尽量把库拆分开来。。
但是个人觉得拆分后细节代码增多,整体思路变得复杂,不如将整个系统整体抽象来的简单;
当然目前数据量较小,时间紧可以这样做,未来考虑扩展性的话,还是拆分开来比较好
资源主要是和业务挂钩的实体
运用最多的是类别,而在一个表中管理多种类别,最好的方法就是添加父主键(pid)

idea创建springboot项目

主要思路:
1为了创建springboot下了jdk1.8
2选择最版本1.51,选择目录空间,名称,选择thymeleaf控件
3创建ok添加pom.xml 通过maven修改jdK,修改sprinboot引用

//修改jdk

        UTF-8
        UTF-8
        1.7
        3.0.8.RELEASE
        2.2.2

//插件配置

        
            
                src/main/java
                
                    **/*.xml
                
            
            
                src/main/resources
            
        
        
            
                org.apache.maven.plugins
                maven-jar-plugin
                3.0.2
                

                    
                        
                            com.schoolbag.SchoolbagApplication
                            true
                            lib/
                        
                        
                            ./
                        
                    
                    
                        ehcache.xml
                        **/xml/*.xml
                        **/*.class
                        templates/**
                        static/**
                    
                
            
            
                maven-assembly-plugin
                3.1.0
                
                    
                    false
                    
                        ./package.xml
                    
                
                
                    
                        make-assembly
                        package
                        
                            single
                        
                    
                
            
        
    

4.关闭项目,将项目从工作空间移到git空间,通过git命令提交到gitlab上(通过.gitignore.xml可以不提交一些没用的文件)
5.自己别人可以从gitlab中获取代码

配置文件

核心 application.properties

#数据库 start
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/erya_new?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=
spring.datasource.password=r

#117.122.222.173
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.druid.async-init=true
#数据库 end


#thymeleaf start
spring.thymeleaf.cache=false
spring.thymeleaf.mode=HTML
#thymeleaf end

server.port=80

#编码
spring.http.encoding.force=true
#身份
spring.application.name=erya_new

#mybatis 路径配置
mybatis.mapper-locations=classpath*:/com/**/mapper/xml/*Mapper.xml
#静态路径
spring.web.upload-location=/opt/
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${spring.web.upload-location}

日志配置




    


    
    



    
    
    
    


    
    
    
    
    
    
    
    
    
    
    
    
    

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


    

    
    
        
        
            
            
            %clr(%d{yyyy-MM-dd HH:mm:ss}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
            
        
    

    
    
        
        ${LOG_HOME}/${appName}-spring.log
        
            
            ${LOG_HOME}/${appName}-spring.%d{yyyy-MM-dd}.log
            ${LOG_MAX_HISTORY}
        
        
            
            ${FILE_LOG_PATTERN}
        
        
            INFO
        
    

    
        
    

mybits_plus使用

下载jar包
按照介绍安装
最大的好处:1.生成实体,mapper,xml
2.mapper与xml可以互相跳转
安装后生成的xml很不好,大神给了jar让我替换
学到替换文件的技巧:
1将新文件拷入
2重命名源文件名,copy名字,之后追加.bak(备份文件)
3将新文件重命名原文件名

打包配置package.xml

存放与pom.xml平级,第一次运行巨慢。。




    package

    
        dir
    
    false

    
        
            src/main/resources
            ${file.separator}
            
                *.xml
                *.properties
            
        
        
            ${project.build.directory}
            ${file.separator}
            
                *.jar
            
        
    
    
        
            lib/
            false
        
    

之后是项目的内部构成:

使用mybits-plus生成model,mapper,xml
bean目录下放自己组装的类
service下除了放mapper引用,还可以放api接口
controller可以分为移动端,pc端,还有API
util 存放常用的工具类,全局常量
html相关都放在resourses下面

mybits中的知识点

1.插入时主键如下声明,在mysql中如果是自增主键,在插入时主键可为空


2.多类别查询判断时,发现查询可以以查询为表如下
select * from (select * from t)
3.做并集和交集
left join t on 组合
inner join () 取交集
4.查询条件一个字段后面会有很多值
t.name in (a,b,c)
5.去重查询
select distinct x form t

js知识点

这个方法的可用性巨高无比

function getVal(s) {
if (s == null || s == undefined)
return ""
}

再说点大神给的建议,前端页面显示的静态图片最好统一放在一个img文件中,数据库只存文件名,这样每次改路径,存文件什么的比较方便,不用改很多

导入数据

由于是一个展示性的项目,所以资源数据巨多,用人力导是不现实的,总结下用poi导excel
导入时网上找的几个好用的方法

 /**
     * @Description 获取Sheet
     * @date 2018-03-28
     * @param file
     * @return org.apache.poi.ss.usermodel.Sheet
     */
    public static Sheet getSheet(File file,Integer page) throws IOException {
        //获取输入流
        final InputStream contactFileInputStream = new FileInputStream(file);
        //获取book
        Workbook workbook = null;
        if (contactFileInputStream!=null) {
            try {
                workbook = WorkbookFactory.create(contactFileInputStream);
            } catch (InvalidFormatException e) {
                e.printStackTrace();
            }
        }
        //获取sheet
        Sheet sheet = null;
        if (null != workbook) {
            if (page == null){
                sheet = workbook.getSheetAt(workbook.getActiveSheetIndex());
            }else {
                sheet = workbook.getSheetAt(page);
            }
        }
        return sheet;

    }
    /**
     * @Description 获取合并的单元格数据
     * @date 2018-05-28
     * @param sheet
     * @param row
     * @param column
     * @return java.lang.String
     */
    public static String getMergedRegionValue(Sheet sheet ,int row , int column){
        int sheetMergeCount = sheet.getNumMergedRegions();

        for(int i = 0 ; i < sheetMergeCount ; i++){
            CellRangeAddress ca = sheet.getMergedRegion(i);
            int firstColumn = ca.getFirstColumn();
            int lastColumn = ca.getLastColumn();
            int firstRow = ca.getFirstRow();
            int lastRow = ca.getLastRow();

            if(row >= firstRow && row <= lastRow){

                if(column >= firstColumn && column <= lastColumn){
                    Row fRow = sheet.getRow(firstRow);
                    Cell fCell = fRow.getCell(firstColumn);
                    return getCellValue(fCell) ;
                }
            }
        }

        return null ;
    }
 /**
     * 合并单元格处理,获取合并行
     * @param sheet
     * @return List
     */
    public  static List getCombineCell(Sheet sheet)
    {
        List list = new ArrayList<>();
        //获得一个 sheet 中合并单元格的数量
        int sheetmergerCount = sheet.getNumMergedRegions();
        //遍历所有的合并单元格
        for(int i = 0; i listCombineCell, Cell cell){
        int xr = 0;
        int firstC = 0;
        int lastC = 0;
        int firstR = 0;
        int lastR = 0;
        for(CellRangeAddress ca:listCombineCell)
        {
            //获得合并单元格的起始行, 结束行, 起始列, 结束列
            firstC = ca.getFirstColumn();
            lastC = ca.getLastColumn();
            firstR = ca.getFirstRow();
            lastR = ca.getLastRow();
            if(cell.getRowIndex() >= firstR && cell.getRowIndex() <= lastR)
            {
                if(cell.getColumnIndex() >= firstC && cell.getColumnIndex() <= lastC)
                {
                    xr = lastR;
                }
            }

        }
        return xr;

    }

关于合并单元格的数据是个很大的坑
基本思想就是先判断是不是合并单元格,如果获取合并内容为null就不是合并单元格
如果是合并单元格,
new StringBuffer
遍历if(row==合并单元格行数 ){
set StringBuffer 和 合并单元格内的数据
}else {
string += 没有合并的数据
}
虽然也可以导word但是感觉,唯一的问题是每行都要看看他能不能在表中查到,肯定不靠谱。。so,看在只有40多条数据的份上用手导了。。

以上 1周项目总结

你可能感兴趣的:(2018-07-02 尔雅平台)