2019-05-05 虽然已经换公司了,但是对缓存的理解还是写在这里
缓存:多用redis, 少用springboot自带的,因为redis可以分布式调用,扩展性比较好
java缓存原理:以一个获取机构logo的方法为例
//创建一个map作为缓存
private Map<String,String> 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
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.7</java.version>
<thymeleaf.version>3.0.8.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
//插件配置
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<mainClass>com.schoolbag.SchoolbagApplication</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>./</Class-Path>
</manifestEntries>
</archive>
<includes>
<include>ehcache.xml</include>
<include>**/xml/*.xml</include>
<include>**/*.class</include>
<include>templates/**</include>
<include>static/**</include>
</includes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<!-- not append assembly id in release file name -->
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>./package.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
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}
日志配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true" scan="true" scanPeriod="2000">
<springProperty scope="context" name="appName" source="spring.application.name"/>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<property name="LOG_HOME" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}}"/>
<!-- 最大保存历史日志天数 -->
<property name="LOG_MAX_HISTORY" value="15"/>
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<logger name="sun" level="OFF"/>
<logger name="javax" level="INFO"/>
<logger name="org.apache.tomcat" level="INFO"/>
<logger name="org.apache.coyote" level="INFO"/>
<logger name="org.apache.catalina" level="INFO"/>
<logger name="org.thymeleaf.standard.expression" level="DEBUG"/>
<logger name="org.thymeleaf.spring4.expression.SPELVariableExpressionEvaluator" level="DEBUG"/>
<logger name="org.thymeleaf.TemplateEngine.CONFIG" level="INFO"/>
<logger name="org.thymeleaf.TemplateEngine.TIMER" level="INFO"/>
<logger name="org.springframework.boot.autoconfigure" level="INFO"/>
<logger name="org.springframework.boot.bind" level="INFO"/>
<logger name="org.springframework.boot.context" level="INFO"/>
<logger name="org.springframework.boot.web.filter" level="INFO"/>
<logger name="net.sf.ehcache.config.ConfigurationHelper" level="INFO"/>
<logger name="net.sf.ehcache.constructs.web.filter.Filter" level="INFO"/>
<logger name="net.sf.ehcache.constructs.web.filter.GzipFilter" level="INFO"/>
<logger name="net.sf.ehcache.statistics.extended.ExtendedStatisticsImpl" level="INFO"/>
<logger name="net.sf.ehcache.store.MemoryStore" level="INFO"/>
<logger name="org.apache.shiro.cache.ehcache.EhCache" level="DEBUG"/>
<logger name="org.apache.shiro.crypto.JcaCipherService" level="DEBUG"/>
<logger name="org.apache.shiro.mgt.DefaultSecurityManager" level="DEBUG"/>
<logger name="org.apache.shiro.session.mgt.AbstractValidatingSessionManager" level="DEBUG"/>
<logger name="org.apache.shiro.spring.web.ShiroFilterFactoryBean" level="DEBUG"/>
<logger name="org.apache.shiro.subject.support.DelegatingSubject" level="DEBUG"/>
<logger name="org.apache.shiro.util.ThreadContext" level="DEBUG"/>
<logger name="org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver" level="ALL"/>
<logger name="org.apache.shiro.web.filter.PathMatchingFilter" level="DEBUG"/>
<logger name="org.apache.shiro.web.mgt.CookieRememberMeManager" level="DEBUG"/>
<logger name="org.apache.shiro.web.servlet.AbstractShiroFilter" level="DEBUG"/>
<logger name="org.apache.shiro.web.servlet.AdviceFilter" level="DEBUG"/>
<logger name="org.apache.shiro.web.servlet.OncePerRequestFilter" level="DEBUG"/>
<logger name="org.apache.shiro.web.servlet.ProxiedFilterChain" level="DEBUG"/>
<logger name="org.apache.shiro.web.servlet.SimpleCookie" level="DEBUG"/>
<logger name="org.mybatis.spring.SqlSessionFactoryBean" level="INFO"/>
<logger name="org.mybatis.spring.SqlSessionUtils" level="INFO"/>
<logger name="org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator" level="INFO"/>
<logger name="org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper" level="INFO"/>
<logger name="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" level="INFO"/>
<logger name="org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator" level="INFO"/>
<logger name="org.springframework.aop.framework.Cglib2AopProxy" level="INFO"/>
<logger name="org.springframework.aop.framework.CglibAopProxy" level="INFO"/>
<logger name="org.springframework.aop.framework.JdkDynamicAopProxy" level="INFO"/>
<logger name="org.springframework.beans.CachedIntrospectionResults" level="INFO"/>
<logger name="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" level="INFO"/>
<logger name="org.springframework.beans.factory.annotation.InjectionMetadata" level="INFO"/>
<logger name="org.springframework.beans.factory.support.DefaultListableBeanFactory" level="INFO"/>
<logger name="org.springframework.beans.factory.xml" level="INFO"/>
<logger name="org.springframework.beans.factory.xml.PluggableSchemaResolver" level="INFO"/>
<logger name="org.springframework.beans.TypeConverterDelegate" level="INFO"/>
<logger name="org.springframework.cache.annotation.AnnotationCacheOperationSource" level="INFO"/>
<logger name="org.springframework.context.annotation.ConfigurationClassEnhancer" level="INFO"/>
<logger name="org.springframework.context.annotation.ConfigurationClassPostProcessor" level="INFO"/>
<logger name="org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider" level="INFO"/>
<logger name="org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader" level="INFO"/>
<logger name="org.springframework.context.event.EventListenerMethodProcessor" level="INFO"/>
<logger name="org.springframework.core.env.PropertySourcesPropertyResolver" level="INFO"/>
<logger name="org.springframework.core.env.StandardEnvironment" level="INFO"/>
<logger name="org.springframework.core.env.MutablePropertySources" level="INFO"/>
<logger name="org.springframework.core.env.SystemEnvironmentPropertySource" level="INFO"/>
<logger name="org.springframework.core.io.support.PathMatchingResourcePatternResolver" level="INFO"/>
<logger name="org.springframework.core.type.classreading.AnnotationAttributesReadingVisitor" level="INFO"/>
<logger name="org.springframework.data.redis.core.RedisConnectionUtils" level="INFO"/>
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="INFO"/>
<logger name="org.springframework.jdbc.core.StatementCreatorUtils" level="INFO"/>
<logger name="org.springframework.jdbc.datasource.DataSourceTransactionManager" level="INFO"/>
<logger name="org.springframework.jdbc.datasource.DataSourceUtils" level="INFO"/>
<logger name="org.springframework.jndi" level="INFO"/>
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
<logger name="org.springframework.session.data.redis.RedisOperationsSessionRepository" level="INFO"/>
<logger name="org.springframework.session.data.redis.RedisSessionExpirationPolicy" level="INFO"/>
<logger name="org.springframework.session.web.http.OnCommittedResponseWrapper" level="INFO"/>
<logger name="org.springframework.session.web.http.SessionRepositoryFilter" level="INFO"/>
<logger name="org.springframework.transaction.interceptor.RuleBasedTransactionAttribute" level="INFO"/>
<logger name="org.springframework.transaction.support.TransactionSynchronizationManager" level="INFO"/>
<logger name="org.springframework.web.context.support.StandardServletEnvironment" level="INFO"/>
<logger name="org.springframework.web.context.support.XmlWebApplicationContext" level="INFO"/>
<logger name="org.springframework.web.method.HandlerMethod" level="DEBUG"/>
<logger name="org.springframework.web.method.support.HandlerMethodArgumentResolverComposite" level="INFO"/>
<logger name="org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite" level="INFO"/>
<logger name="org.springframework.web.servlet.DispatcherServlet" level="TRACE"/>
<logger name="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" level="INFO"/>
<logger name="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" level="INFO"/>
<logger name="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" level="INFO"/>
<logger name="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" level="INFO"/>
<logger name="org.springframework.web.servlet.resource.ResourceHttpRequestHandler" level="DEBUG"/>
<logger name="org.springframework.web.servlet.resource.PathResourceResolver" level="DEBUG"/>
<logger name="org.springframework.web.socket.server.support.WebSocketHandlerMapping" level="DEBUG"/>
<logger name="org.springframework.web.socket.sockjs.transport.handler.HtmlFileTransportHandler" level="DEBUG"/>
<logger name="org.springframework.web.socket.sockjs.transport.handler.XhrStreamingTransportHandler" level="DEBUG"/>
<logger name="org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession" level="DEBUG"/>
<logger name="com.github.mapper" level="INFO"/>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--<withJansi>true</withJansi>-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<!--<pattern>${CONSOLE_LOG_PATTERN}</pattern>-->
<pattern>%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}</pattern>
<!--<pattern><pattern>[%-5p][%d{yyyy-MM-dd HH:mm:ss}]%c[%F]:%L - <%m>%n</pattern></pattern>-->
</encoder>
</appender>
<!-- 消息日志,记录项目所有消息记录 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 如果指定了file属性,当天的文件名为file属性值 -->
<file>${LOG_HOME}/${appName}-spring.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/${appName}-spring.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>${LOG_MAX_HISTORY}</maxHistory>
</rollingPolicy>
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
mybits_plus使用
下载jar包
按照介绍安装
最大的好处:1.生成实体,mapper,xml
2.mapper与xml可以互相跳转
安装后生成的xml很不好,大神给了jar让我替换
学到替换文件的技巧:
1将新文件拷入
2重命名源文件名,copy名字,之后追加.bak(备份文件)
3将新文件重命名原文件名
打包配置package.xml
存放与pom.xml平级,第一次运行巨慢。。
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>package</id>
<formats>
<format>dir</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>src/main/resources</directory>
<outputDirectory>${file.separator}</outputDirectory>
<includes>
<include>*.xml</include>
<include>*.properties</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>${file.separator}</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>lib/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
</assembly>
之后是项目的内部构成:
使用mybits-plus生成model,mapper,xml
bean目录下放自己组装的类
service下除了放mapper引用,还可以放api接口
controller可以分为移动端,pc端,还有API
util 存放常用的工具类,全局常量
html相关都放在resourses下面
mybits中的知识点
1.插入时主键如下声明,在mysql中如果是自增主键,在插入时主键可为空
<insert id="insert" parameterType="com.chaoxing.erya.model.TRes" useGeneratedKeys="true"
keyProperty="id">
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<CellRangeAddress>
*/
public static List<CellRangeAddress> getCombineCell(Sheet sheet)
{
List<CellRangeAddress> list = new ArrayList<>();
//获得一个 sheet 中合并单元格的数量
int sheetmergerCount = sheet.getNumMergedRegions();
//遍历所有的合并单元格
for(int i = 0; i<sheetmergerCount;i++)
{
//获得合并单元格保存进list中
CellRangeAddress ca = sheet.getMergedRegion(i);
list.add(ca);
}
return list;
}
/**
* @Description 获取合并单元格的行数
* @date 2018-07-03
* @param listCombineCell
* @param cell
* @return int
*/
public static int getRowNum(List<CellRangeAddress> 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周项目总结
网友评论