1.Git操作命令
Git global setup
git config --global user.name "xxx"
git config --global user.email "xxx2035@163.com"
Create a new repository
git clone xxx.git
cd data_filtering
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
Push an existing folder
cd existing_folder
git init
git remote add origin xxx.git
git add .
git commit -m "Initial commit"
git push -u origin master
Push an existing Git repository
cd existing_repo
git remote rename origin old-origin
git remote add origin xxx.git
git push -u origin --all
git push -u origin --tags
mvn archetype:generate -DgroupId=com.ctsi.demo -DartifactId=ctsibiyii_web -Dversion=1.0.0-SNAPSHOT -DarchetypeGroupId=com.ctbiyi.sampleapp -DarchetypeArtifactId=biyi-app-archetype -DarchetypeVersion=4.7.1 -DdbAddress=127.0.0.1 -DdbPort=3306 -DdbName=ctsibiyi -DdbUser=root -DdbPassword=root -DdbTables=cms_client,cms_salesmanager,cms_record,cms_client_res,cms_enclosure -Ddatabase=mysql -DdataAccess=mybatis -DuserName=biyijonie -Dgoals=mybatis-generator:generate
2.getUrlWithParams 拼接功能
public static String getUrlWithParams(String url, Map<String, String> params) {
String paramsString = url;
if (!paramsString.contains("?")) paramsString += "?";
for (Map.Entry<String, String> entry:params.entrySet()) {
if (!paramsString.endsWith("&")) paramsString += "&";
paramsString += entry.getKey()+"="+entry.getValue()+"&";
}
return paramsString.substring(0,paramsString.length()-1);
}
for (Map.Entry<String, String> entry:params.entrySet()) {}
3.NumberFormat
java对文字, 数字的格式化,是有一个公共的父类的Format。
NumberFormat和DecimalFormat都是它的子类*关于数字的*。
DateFormat和SimpleDateFormat也是它的子类关于文字的。
NumberFormat和DecimalFormat是线程不安全的
NumberFormat帮助您格式化和解析任何区域设置的数字。您的代码可以完全独立于小数点,千位分隔符的区域设置约定,甚至是使用的特定十进制数字,或者数字格式是否为十进制。
DecimalFormat是NumberFormat十进制数字格式的具体子类 。它具有多种功能,旨在解析和格式化任何语言环境中的数字,包括支持西方,阿拉伯语和印度语数字。它还支持不同类型的数字,包括整数(123),定点数(123.4),科学记数法(1.23E4),百分比(12%)和货币金额(123美元)。所有这些都可以本地化。
获取NumberFormat实例
//创建 一个整数格式 地区用系统默认的
NumberFormat integerNumber = NumberFormat.getIntegerInstance(Locale.getDefault());
使用getInstance或getNumberInstance获取正常的数字格式。
使用getIntegerInstance得到的整数格式。
使用getCurrencyInstance来获取货币数字格式。
使用getPercentInstance获取显示百分比的格式
NumberFormat numberFormat = NumberFormat.getInstance();
// 设置精确到小数点后5位
numberFormat.setMaximumFractionDigits(4);
numberFormat.setRoundingMode(RoundingMode.DOWN);
String res = numberFormat.format((float) managedCount / (float) netElementTotal * 100);
String netElementRate = res + "%";
result.put("netElementRate", netElementRate);
4. java8分别对于Map的key和value值进行排序
1、map 根据value排序
Map<String,BigDecimal> map =new HashMap<>();
map.put(“one”, 0.08);
map.put(“two”, 0.1);
map.put(“three”, 0.2);
map.put(“four”, 0.91);
上面是项目中的一个中间结果,我们需要对这个map根据value值倒序排序,下面给出工具类:
public <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
Map<K, V> result = new LinkedHashMap<>();
map.entrySet().stream()
.sorted(Map.Entry.<K, V>comparingByValue()
.reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
return result;
}
2、map 根据key排序
想根据map的key进行排序,需要对上面的工具类进行小小的修改,代码如下:
public <K extends Comparable<? super K>, V > Map<K, V> sortByKey(Map<K, V> map) { Map<K, V> result = new LinkedHashMap<>(); map.entrySet().stream() .sorted(Map.Entry.<K, V>comparingByKey() .reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue())); return result; }
我们可以看到,如果我们需要根据key排序,就需要让key 继承 Comparable ,也就说我们需要对待排序的字段继承 Comparable接口。另一个问题就是,上面的这种写法排序效果是 降序排序,如果我们需要升序排序的话,只需要将上面的.reversed()关键字限制去掉即可。
public <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) { Map<K, V> result = new LinkedHashMap<>(); map.entrySet().stream() .sorted(Map.Entry.<K, V>comparingByValue() ).forEachOrdered(e -> result.put(e.getKey(), e.getValue())); return result; }
5.时间(7天)
private List<String> getDaysBetwwen(int days) { List<String> dayss = new ArrayList<>(); Calendar start = Calendar.getInstance(); start.setTime(getDateAdd(days)); Long startTIme = start.getTimeInMillis(); Calendar end = Calendar.getInstance(); end.setTime(new Date()); Long endTime = end.getTimeInMillis(); Long oneDay = 1000 * 60 * 60 * 24l; Long time = startTIme; while (time <= endTime) { Date d = new Date(time); DateFormat df = new SimpleDateFormat("yyyyMMdd"); dayss.add(df.format(d)); time += oneDay; } return dayss; }
private Date getDateAdd(int days) {
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, -days);
return c.getTime();
}
List<DcResManageResult> dcResManageResults = dcResManageResults1.stream().sorted(Comparator.comparing(DcResManageResult::getCheckItem)).collect(Collectors.toList());
6.日期比较方式之Date的after和before
1. after/before
使用after/before进行日期比较时注意:
date1.after(date2)
当date1大于date2时,返回true,当小于等于时,返回false;
date1.before(date2)
当date1小于date2时,返回true,当大于等于时,返回false.
!currentDate.before(startDate) && !currentDate.after(engMPTask.getEndDate())
相当于
currentDate.getTime() >= startDate.getTime() && currentDate.getTime() <= engMPTask.getEndDate().getTime()
2. 用date.getTime() 返回long,再进行比较
if(dt1.getTime() < dt2.getTime()) {}
//-------------------
ZonedDateTime.now():获取当前时间
3. compareTo
两个Date类型的变量可以通过compareTo方法来比较。此方法的描述是这样的:如果参数 Date 等于此 Date,则返回值 0;如果此 Date 在 Date 参数之前,则返回小于 0 的值;如果此 Date 在 Date 参数之后,则返回大于 0 的值。
实际上比较的是自1970 年 1 月 1 日 00:00:00 GMT以来的毫秒数。毫秒数越大的时间越大。
String DateStr1 = "2011-10-1 10:20:16";String DateStr2 = "2011-10-07 15:50:35";DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date dateTime1 = dateFormat.parse(DateStr1);Date dateTime2 = dateFormat.parse(DateStr2);int i = dateTime1.compareTo(dateTime2); System.out.println(i < 0);
4. SimpleDateFormat的format方法将日期型转化成时间或日期的字符串,然后再比较字符串
日期型转换为字符串:
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒SSS毫秒"); String str=sdf.format(date);
beginTime.compareTo(endTime)<0时,开始时间小于结束时间
注意:如果一个日期格式是2016-01-01,但是另一个日期格式是2016-1-1时,直接使用字符串进行比较就会存在问题。
7.三种加载配置文件的方式
三种方式加载properties配置文件
1.三种加载方式的编码
具体代码如下所示:
public class PropertiesLoader {
public static void main(String[] args) throws IOException {
//方式一 、使用属性对象Properties和文件输入流对象FileInputStream加载properties配置文件。
Properties properties = new Properties();//创建属性对象
FileInputStream fileInputStream = new FileInputStream("D:\xxxx.properties");//创建文件输入流对象
properties.load(fileInputStream);
System.out.println("dispatcher.conn.thread="+properties.getProperty("dispatcher.conn.thread"));
System.out.println("dispatcher.request.thread="+properties.getProperty("dispatcher.request.thread"));
System.out.println("dispatcher.response.thread="+properties.getProperty("dispatcher.response.thread"));
//注意:此处可以获取带双引号的值,需要双等号。
System.out.println("dispatcher.response.thread1="+properties.getProperty("dispatcher.response.thread1"));
//注意:此处获取的值为null,因为value被双引号包裹。
System.out.println("dispatcher.response.thread2="+properties.getProperty("dispatcher.response.thread2"));
System.out.println("===================================分割线1===================================");
//方式二、通过属性对象Properties和类加载器加载properties配置文件,注意配置文件的位置必须在src目录下。
Properties properties2 = new Properties();
InputStream in = PropertiesLoader.class.getClassLoader().getResourceAsStream("xxxx.properties");
properties2.load(in);
System.out.println("dispatcher.conn.thread="+properties2.getProperty("dispatcher.conn.thread"));
System.out.println("dispatcher.request.thread="+properties2.getProperty("dispatcher.request.thread"));
System.out.println("dispatcher.response.thread="+properties2.getProperty("dispatcher.response.thread"));
//注意:此处可以获取带双引号的值,需要双等号。
System.out.println("dispatcher.response.thread1="+properties2.getProperty("dispatcher.response.thread1"));
//注意:此处获取的值为null,因为value被双引号包裹。
System.out.println("dispatcher.response.thread2="+properties2.getProperty("dispatcher.response.thread2"));
System.out.println("===================================分割线2===================================");
//方式三、通过资源包对象ResourceBundle和基名(即文件前缀名)加载properties配置文件,注意配置文件的位置必须在src目录下。
ResourceBundle bundle = ResourceBundle.getBundle("xxxx2");
System.out.println("dispatcher.conn.thread="+bundle.getString("dispatcher.conn.thread"));
System.out.println("dispatcher.request.thread="+bundle.getString("dispatcher.request.thread"));
System.out.println("dispatcher.response.thread="+bundle.getString("dispatcher.response.thread"));
//注意:此处可以获取带双引号的值,需要双等号。
System.out.println("dispatcher.response.thread1="+bundle.getString("dispatcher.response.thread1"));
//注意此处会报异常,因为value被双引号包裹。
System.out.println("dispatcher.response.thread2="+bundle.getString("dispatcher.response.thread2"));
}
}
Resource resource = resourceLoader.getResource("classpath:resource.properties");
InputStream is = resource.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String data = null;
while((data = br.readLine()) != null) {
System.out.println(data);
}
//---------------------------------------------------------------------
new BufferedReader(new InputStreamReader(resourceLoader.getResource("classpath:resource.properties").getInputStream)))
InputStream in = null; Properties properties = null; try { in = fds.class.getResourceAsStream("/config/ems.yml"); System.out.println(in); properties = new Properties(); } catch (Exception e) { e.printStackTrace(); } try { properties.load(new InputStreamReader(in,"utf-8")); } catch (IOException e) { e.printStackTrace(); } String logFilePath = properties.getProperty("logFilePath"); System.out.println(logFilePath);
8. es 动态索引
关键技术点: Spel表达式 (通过调用方法来获取新的索引名,方法内处理新索引名的生成逻辑)
**实体类部分代码**
从表达式中可以看出:esConfig 是一个bean,调用了getXX方法。
@Document(indexName = "#{esConfig.getApiCallIndexName()}")public class ApiCallRecord { /** * 平台流水号 */ @Id @Field(type = FieldType.Keyword) private String transId; 。。。。。。 }
动态索引Bean代码:
将改类注册成Bean,名称为“esConfig”,其中apiCallIndexNamePrefix,是索引的前缀(为了通用,让它从配置文件取,如果没有那么就设置默认值“api_call_rec_”),方法中的逻辑就是生成逻辑,这样就能够生成api_call_rec_yyyy_MM这样的索引了。
@Component(value = "esConfig")public class ElasticSearchConfiguration { @Value("${esConfig.apiCallIndexName:api_call_rec_}") private String apiCallIndexNamePrefix; public String getApiCallIndexName() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM"); return apiCallIndexNamePrefix + LocalDateTime.now().format(formatter); }}
从Kibana中也能看到确实是生成了动态索引(我最开始是获取当前时间“秒”来测试的,每次处理逻辑后基本都会有新的索引创建。)
9. CollectionUtils.isEmpty(集合)
package org.apache.commons.collections;
源码如下:
public static boolean isEmpty(Collection coll) { return coll == null || coll.isEmpty(); }
CollectionUtils.isEmpty(集合) 用来对集合null和空的判断
10.数据库地址
?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
11. vs code 权限问题
解决这个问题:
看看错误信息:
npm : 无法加载文件 D:DevPath
odejs
pm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
所在位置 行:1 字符: 1
-
npm install mini-program-iconfont-cli --save-dev
-
+ CategoryInfo : SecurityError: (:) [],PSSecurityException
报错信息:
我遇到这个错误是:我的固态坏了,然后换了个新固态,环境变量就没了,以前安装node时候,使用npm就没这个错,现在就出现了这个权限错误(但是node -v能查看版本号)
下面是解决方法
因为在此系统上禁止运行脚本,也就是说没有权限,先用下面命令看看:get-ExecutionPolicy如果输出:
Restricted上面表示受限制的,表示状态是禁止的,那就给个权限:Set-ExecutionPolicy -Scope CurrentUser再输入:
RemoteSigned
以上就ok了,如果想验证一下就再输入get-ExecutionPolicy,输出RemoteSigned
12. StringTokenizer
Java StringTokenizer 属于 java.util 包,用于分隔字符串。
StringTokenizer 构造方法:
- 1. StringTokenizer(String str) :构造一个用来解析 str 的 StringTokenizer 对象。java 默认的分隔符是空格("")、制表符( )、换行符( )、回车符( )。
- 2. StringTokenizer(String str, String delim) :构造一个用来解析 str 的 StringTokenizer 对象,并提供一个指定的分隔符。
- 3. StringTokenizer(String str, String delim, boolean returnDelims) :构造一个用来解析 str 的 StringTokenizer 对象,并提供一个指定的分隔符,同时,指定是否返回分隔符。
StringTokenizer 常用方法:
-
1. int countTokens():返回nextToken方法被调用的次数。
-
2. boolean hasMoreTokens():返回是否还有分隔符。
-
3. boolean hasMoreElements():判断枚举 (Enumeration) 对象中是否还有数据。
-
4. String nextToken():返回从当前位置到下一个分隔符的字符串。
-
5. Object nextElement():返回枚举 (Enumeration) 对象的下一个元素。
-
6. String nextToken(String delim):与 4 类似,以指定的分隔符返回结果。
import java.util.*; public class Main { public static void main(String[] args) { String str = "runoob,google,taobao,facebook,zhihu"; // 以 , 号为分隔符来分隔字符串 StringTokenizer st=new StringTokenizer(str,","); while(st.hasMoreTokens()) { System.out.println(st.nextToken()); } } }
输出结果为:
runoob google taobao facebook zhihu
13. new Parse(new DiamnodetplStrategy())
new Parse(new DiamnodetplStrategy())
Parse.java
public class Parse {
private ParseStrategy parseStrategy;
public Parse(ParseStrategy parseStrategy) {
this.parseStrategy = parseStrategy;
}
public void parse(String key, List<String> values, UdmUserData udmUserData) {
this.parseStrategy.parse(key, values, udmUserData);
}
}
DiamnodetplStrategy.java
public class DiamnodetplStrategy implements ParseStrategy { @Override public void parse(String key, List<String> values, UdmUserData udmUserData) { udmUserData.setDIAMNODETPL_ID(values.get(0)); }}
ParseStrategy.java
public interface ParseStrategy {
void parse(String key, List<String> values, UdmUserData udmUserData);
}
14.查看主机编号
15.toZonedDateTime
public static ZonedDateTime toZonedDateTime(Long time){
String LONG_DATE = "yyyy-MM-dd HH:mm:ss:SSS";
SimpleDateFormat sdf = new SimpleDateFormat(LONG_DATE);
Date createDate = new Date(time);
String format = sdf.format(createDate);
DateTimeFormatter beijingFormatter = DateTimeFormatter.ofPattern(LONG_DATE).withZone(ZoneId.of("Asia/Shanghai"));
if(StringUtils.isBlank(format)){
return null;
}
ZonedDateTime beijingDateTime = ZonedDateTime.parse(format, beijingFormatter);
ZonedDateTime utc = beijingDateTime.withZoneSameInstant(ZoneId.of("UTC"));
return utc;
}
16.list去重
用一个空list存放遍历后的数据
@Test
public void dis1() {
List<User> result = new LinkedList<>();
for (User user : users) {
boolean b = result.stream().anyMatch(u -> u.getId().equals(user.getId()));
if (!b) {
result.add(user);
}
}
System.out.println(result);
}
17.jar包和war包
1、jar包不包含wabapp目录,jar包主要使用在通用功能,不包含webapp目录,打的jar包可以直接放在其他项目的lib使用,使用内部tomcat启动。
2、war包方式,包含webapp目录,打包时包含webapp目录,使用外部容器进行启动。
18.reids
https://www.bilibili.com/video/BV19X4y1G7S4?from=search&seid=1702179242620498042
添加enablecahine注解
/**
* 配置redistemplate序列化
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 选择redis作为默认缓存工具
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
//设置缓存有效一小时
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.
defaultCacheConfig().entryTtl(Duration.ofHours(1));
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)).cacheDefaults(redisCacheConfiguration).build();
}
/**
* 配置redistemplate相关配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 值采用json序列化
template.setValueSerializer(jacksonSeial);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
/**
* 对hash类型的数据操作
*/
public HashOperations<String,String,Object> hashOperations(RedisTemplate<String,Object> redisTemplate){
return redisTemplate.opsForHash();
}
/**
* 对redis字符串类型数据库操作
*/
@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForValue();
}
/**
* 对链表类型的数据操作
*/
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
/**
* 对无序集合Set操作
*/
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
/**
* 对有序集合
*/
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private RedisTemplate redisTemplate;
//查所有用户
public List<User> queryAll(){
return userDao.queryAll();
}
/**
* 获取用户策略:先从缓存中获取用户,没有则读mysql数据,再将数据写入缓存
*/
public User findUserById(int id){
String key = "user_"+id;
ValueOperations<String,User> operations = redisTemplate.opsForValue();
//判断redis中是否有键为key的缓存
boolean hasKey = redisTemplate.hasKey(key);
if(hasKey){
User user = operations.get(key);
System.out.println("从缓存中获取数据:"+user.getUserName());
System.out.println("-----------------------------");
return user;
}else{
User user = userDao.findUserById(id);
System.out.println("查询数据库获取数据:"+user.getUserName());
System.out.println("------------写入缓存---------------------");
//写入缓存
operations.set(key,user,5, TimeUnit.HOURS);
return user;
}
}
//删除用户策略:删除数据表中数据,然后删除缓存
public int deleteUserById(int id){
int result = userDao.deleteUserById(id);
String key = "user_"+id;
if(result!=0){
boolean hasKey = redisTemplate.hasKey(key);
if(hasKey){
redisTemplate.delete(key);
System.out.println("删除了缓存中的key:"+key);
}
}
return result;
}
/**
* 更新用户策略:先更新数据表,成功之后,删除原来的缓存,再更新缓存
*/
public int updateUser(User user) {
ValueOperations<String, User> operations = redisTemplate.opsForValue();
int result = userDao.updateUser(user);
if (result != 0) {
String key = "user_" + user.getId();
boolean haskey = redisTemplate.hasKey(key);
if (haskey) {
redisTemplate.delete(key);
System.out.println("删除缓存中的key-----------> " + key);
}
// 再将更新后的数据加入缓存
User userNew = userDao.findUserById(user.getId());
if (userNew != null) {
operations.set(key, userNew, 3, TimeUnit.HOURS);
}
}
return result;
}
}
server:
port: 8081
#数据库连接
spring:
datasource:
url: jdbc:mysql://localhost:3306/springboot?useUnicode=true
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
## Redis 配置
redis:
## Redis数据库索引(默认为0)
database: 0
## Redis服务器地址
host: 127.0.0.1
## Redis服务器连接端口
port: 6379
## Redis服务器连接密码(默认为空)
password:
jedis:
pool:
## 连接池最大连接数(使用负值表示没有限制)
#spring.redis.pool.max-active=8
max-active: 8
## 连接池最大阻塞等待时间(使用负值表示没有限制)
#spring.redis.pool.max-wait=-1
max-wait: -1
## 连接池中的最大空闲连接
#spring.redis.pool.max-idle=8
max-idle: 8
## 连接池中的最小空闲连接
#spring.redis.pool.min-idle=0
min-idle: 0
## 连接超时时间(毫秒)
timeout: 1200
#将themilef的默认缓存禁用,热加载生效
thymeleaf:
cache: false
#mybatis的下划线转驼峰配置
configuration:
map-underscore-to-camel-case: true
#另外一种打印语句的方式
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#打印sql时的语句
logging:
level:
com:
acong:
dao: debug
file:
path: d:/logs/demo
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis与spring boot2.x整合包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
19.appropertis文件解析
log-parser-strategy.properties
################日志解析任务,各省信息配置####################################
########################广东省解析ems网元日志信息###########################
#部署放开下一行
#log-parser.provinces.NOD00v.ems.scrtlog-path=/RDSP/5GC/LOG/GDY/HW/SCRTLOG/EMS/
#本地测试放开此行,并注释上一行
log-parser.provinces.NOD00v.ems.scrtlog-path=D:\Ctsi\LogDate\GDY\HW\SCRTLOG\EMS
#log-parser.provinces.NOD00v.ems.oplog-path=/RDSP/5GC/LOG/GDY/HW/OPLOG/EMS/
log-parser.provinces.NOD00v.ems.oplog-path=D:\Ctsi\LogDate\GDY\HW\OPLOG\EMS
###############################福建省解析ems网元日志信息############################
#log-parser.provinces.NOD00l.ems.scrtlog-path=/RDSP/5GC/LOG/FJM/ZX/SCRTLOG/EMS/
log-parser.provinces.NOD00l.ems.scrtlog-path=D:\Ctsi\LogDate\FJM\ZX\SCRTLOG\EMS
#log-parser.provinces.NOD00l.ems.oplog-path=/RDSP/5GC/LOG/FJM/ZX/OPLOG/EMS/
log-parser.provinces.NOD00l.ems.oplog-path=D:\Ctsi\LogDate\FJM\ZX\OPLOG\EMS
/**
* 日志解析策略配置
*/
@Configuration
@ConfigurationProperties(prefix = "log-parser", ignoreUnknownFields = false)
@PropertySource("classpath:config/log-parser-strategy.properties")
@Data
@Component
public class LogParserStrategyConfiguration {
private Map<String,String> provinces;
}
使用
/**
* 读取配置文件分别解析
*/
Map<String, String> provinces = logParserStrategyConfiguration.getProvinces();
for (Map.Entry<String, String> entry : provinces.entrySet()) {
String logmoudle=entry.getKey().split("\.")[2];//日志的模式
String nodecode=entry.getKey().split("\.")[0];//日志的编码
String filepath=entry.getValue();//路径
if ("oplog-path".equals(logmoudle)){
parserEmsLogCommonService.parserEmsLogComm(filepath ,nodecode );
}
if ("scrtlog-path".equals(logmoudle)){
parserEmsLogCommonService.parserEmsScrtLog(filepath , nodecode);
}
}
}
20 linux
进入编辑模式
命令 | 含义 |
---|---|
i和I | i在光标前插入,I在行首插入。 |
a和A | a在光标后插入,A在行末插入. |
o和O | o在光标所在行下一行插入,O在光标所在行上一行插入. |
^和$ |
^移动到行首,$ 移动到行末 |
---|---|
G和gg | G文档最后一行,gg文档第一行 |
ctrl+f、ctrl+b | 向前翻屏、向后翻屏 |
ctrl+d、ctrl+u | 向前半屛、向后半屛 |
{ 和 } | {向上移动一段,}向后移动一段 |
w和b | w向前移动一个单词,b向后移动一个单词 |
2.4 删除命令
命令 | 含义 |
---|---|
X和x | x删除光标后一个字符,X删除光标前一个字符,包含光标位置字符 |
dd和n dd | dd删除所在行,5 dd删除指定行数 |
d0和D | d0删除光标前本行所有内容,D删除光标后本行所有内容,包含光标位置字符 |
dw | 删除光标所在位置的字,包含光表所在位置字符 |
2.3 撤销命令
命令 | 含义 |
---|---|
u | 一步一步撤销 |
ctrl + r | 反撤销 |
2.6 移动命令
命令 | 含义 |
---|---|
>> | 文本行右移动 |
<< | 文本行左移动 |
复制粘贴:
命令 | 含义 |
---|---|
yy、n yy、y$ | y^ yy复制当前行,5 yy复制5行 |
p | 在光标所在位置向下新开一行粘贴 |
查找替换:
命令 | 含义 |
---|---|
命令模式下,r和R | r替换当前字符,R替换光标后的字符 |
末行模式下,/ + str | n查找下一个,N查找前一个 |
末行模式下,%s/abc/123/g | 将文件中所有abc替换为123 |
末行模式下,1, 10s/abc/123/g | 将第一行至第10行之间的abc替换成123 |
21、线程安全自增
public class Count {
private static AtomicInteger counter = new AtomicInteger(0);
public static int getCount(){
// 线程安全,以原子方式将当前值加1,注意:这里返回的是自增前的值。
return counter.getAndIncrement();
}
}
22、sql trim
" <trim prefix='and' prefixOverrides='and'>",
" status = '未恢复'",
" </trim>",
UserInfoMapper.xml 内容如下:
<select id="findUserInfoByUnoQuantity" parameterType="Map"
resultMap="UserInfoResult">
select * from userinfo
<where>
<if test="department!=null">
and department like #{department}
</if>
<if test="gender!=null">
AND gender=#{gender}
</if>
<if test="position!=null">
AND position like #{position}
</if>
</where>
</select>
【解释】
a.select之后没有直接写Sql语句的where,而是使用
b.按照标准写法,第一个where
标签帮助我们自动的移除了第一个AND链接。但是,第二个之后的
c.如果没有一个条件符合,则返回所有条目。
d.
3.修改单元测试方法,如下:
@Test
public void testSeletOne() {
try {
Map<String, Object> map = new HashMap<String, Object>();
map.put("department", "1");
map.put("gender", "1");
map.put("position", "工程师");
Departments d = new Departments("2", "%售%");
map.put("d", d);
UserInfoDao userInfo = sqlSession.getMapper(UserInfoDao.class);
List<UserInfo> UIList = userInfo.findUserInfoByUnoQuantity(map);
for (UserInfo ui : UIList) {
System.out.println(ui.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
4.运行单元测试方法,观察输出即可。
5.结论:where 元素知道只有在一个以上的
1.该标签的功能与
2.修改Mapper文件,具体内容如下:
<select id="findUserInfoByTrim" parameterType="Map"
resultMap="UserInfoResult">
select * from userinfo
<trim prefix="where" prefixOverrides="and|or">
<if test="department!=null">
AND department like #{department}
</if>
<if test="gender!=null">
AND gender=#{gender}
</if>
<if test="position!=null">
AND position like #{position}
</if>
</trim>
</select>
【解释】
a.我们使用<trim>
替代<where>
标签。
b.属性 prefix="where"
表示:加前缀 where
。
c.属性prefixOverrides="and|or"
表示:自动覆盖第一个and
或者or
.
d.后缀的用法类似;
23、BigDecimal
System.out.println(new BigDecimal(0.99));
System.out.println(new BigDecimal("0.99"));
System.out.println(BigDecimal.valueOf(0.99));
System.out.println(new BigDecimal(Double.valueOf(0.99)));
System.out.println(new BigDecimal(Double.valueOf(0.99).toString()));
输出结果如下:
0.9899999999999999911182158029987476766109466552734375
0.99
0.99
0.9899999999999999911182158029987476766109466552734375
0.99
可以看到new BigDecimal(double)类型时,小数的精度出现扩展。
总结:
如果使用new BigDecimal()时,尽可能转换为String,或者直接使用BigDecimal.valueof(double)
24、checkObjAllFieldsIsNull
package com.ctsi.newnetwork.enums;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
/**
* @author jonie
* @date 2021/9/1
* @description:
*/
public class kk {
private String name;
private String gender;
/**
* 如果属性类型为基本数据类型,则会有默认值
* 影响正确判断,请特别注意
*/
// private int age;
private Integer age;
public kk() {
}
public kk(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public static void main(String[] args) {
kk user1 = new kk("Jack", "male", 17);
kk user2 = new kk();
boolean u1Flag = checkObjAllFieldsIsNull(user1);
boolean u2Flag = checkObjAllFieldsIsNull(user2);
System.out.println("user1 是否为空:" + u1Flag);
System.out.println("user2 是否为空:" + u2Flag);
}
/**
* 判断对象中属性值是否全为空
*
* @param object
* @return
*/
public static boolean checkObjAllFieldsIsNull(Object object) {
if (null == object) {
return true;
}
try {
for (Field f : object.getClass().getDeclaredFields()) {
f.setAccessible(true);
System.out.print(f.getName() + ":");
System.out.println(f.get(object));
if (f.get(object) != null && StringUtils.isNotBlank(f.get(object).toString())) {
return false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
25、@JsonFormat与@DateTimeFormat注解的使用
@JsonFormat与@DateTimeFormat注解的使用
背景:从数据库获取时间传到前端进行展示的时候,我们有时候可能无法得到一个满意的时间格式的时间日期,在数据库中显示的是正确的时间格式,获取出来却变成了很丑的时间戳,@JsonFormat注解很好的解决了这个问题,我们通过使用@JsonFormat可以很好的解决:后台到前台时间格式保持一致的问题,其次,另一个问题是,我们在使用WEB服务的时,可能会需要用到,传入时间给后台,比如注册新用户需要填入出生日期等,这个时候前台传递给后台的时间格式同样是不一致的,而我们的与之对应的便有了另一个注解,@DataTimeFormat便很好的解决了这个问题,接下来记录一下具体的@JsonFormat与DateTimeFormat的使用过程。
声明:关于@JsonFormat的使用,一定要导入正确完整的包。
1.注解@JsonFormat
1.使用maven引入@JsonFormat所需要的jar包,我贴一下我这里的pom文件的依赖
<!--JsonFormat-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
2.在你需要查询出来的时间的数据库字段对应的实体类的属性上添加@JsonFormat
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
public class TestClass {
//设置时区为上海时区,时间格式自己据需求定。
@JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
private Date testTime;
public Date gettestTime() {
return testTime;
}
public void settestTime(Date testTimee) {
this.testTime= testTime;
}
}
这里解释一下:@JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
pattern:是你需要转换的时间日期的格式
timezone:是时间设置为东八区,避免时间在转换中有误差
提示:@JsonFormat注解可以在属性的上方,同样可以在属性对应的get方法上,两种方式没有区别
3.完成上面两步之后,我们用对应的实体类来接收数据库查询出来的结果时就完成了时间格式的转换,再返回给前端时就是一个符合我们设置的时间格式了
2.注解@DateTimeFormat
1.@DateTimeFormat的使用和@jsonFormat差不多,首先需要引入是spring还有jodatime,spring我就不贴了
<!-- joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.3</version>
</dependency>
2.在controller层我们使用spring mvc 表单自动封装映射对象时,我们在对应的接收前台数据的对象的属性上加@@DateTimeFormat
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date symstarttime;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date symendtime;
我这里就只贴这两个属性了,这里我两个注解都同时使用了,因为我既需要取数据到前台,也需要前台数据传到后台,都需要进行时间格式的转换,可以同时使用
3.通过上面两个步骤之后,我们就可以获取一个符合自定义格式的时间格式存储到数据库了
总结:
注解@JsonFormat主要是后台到前台的时间格式的转换
注解@DataFormAT主要是前后到后台的时间格式的转换
26、Multimap 一个key可以映射多个value的HashMap
Multimap<String, Integer> map = ArrayListMultimap.create();
map.put("key", 1);
map.put("key", 2);
Collection<Integer> values = map.get("key");
System.out.println(map); // 输出 {"key":[1,2]}
// 还能返回你以前使用的臃肿的Map
Map<String, Collection<Integer>> collectionMap = map.asMap();
省得你再创建 Map<String, List>
27、BiMap 一种连value也不能重复的HashMap
BiMap<String, String> biMap = HashBiMap.create();
// 如果value重复,put方法会抛异常,除非用forcePut方法
biMap.put("key","value");
System.out.println(biMap); // 输出 {"key":"value"}
// 既然value不能重复,何不实现个翻转key/value的方法,已经有了
BiMap<String, String> inverse = biMap.inverse();
System.out.println(inverse); // 输出 {"value":"key"}
这其实是双向映射,在某些场景还是很实用的。
28、Table 一种有两个key的HashMap
// 一批用户,同时按年龄和性别分组
Table<Integer, String, String> table = HashBasedTable.create();
table.put(18, "男", "yideng");
table.put(18, "女", "Lily");
System.out.println(table.get(18, "男")); // 输出 yideng
// 这其实是一个二维的Map,可以查看行数据
Map<String, String> row = table.row(18);
System.out.println(row); // 输出 {"男":"yideng","女":"Lily"}
// 查看列数据
Map<Integer, String> column = table.column("男");
System.out.println(column); // 输出 {18:"yideng"}
29、Multiset 一种用来计数的Set
Multiset<String> multiset = HashMultiset.create();
multiset.add("apple");
multiset.add("apple");
multiset.add("orange");
System.out.println(multiset.count("apple")); // 输出 2
// 查看去重的元素
Set<String> set = multiset.elementSet();
System.out.println(set); // 输出 ["orange","apple"]
// 还能查看没有去重的元素
Iterator<String> iterator = multiset.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 还能手动设置某个元素出现的次数
multiset.setCount("apple", 5);
30、logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<contextName>logs</contextName>
<!-- 日志位置 -->
<property name="log.path" value="./data/serverLogs/" />
<!-- 日志保留时长 -->
<property name="log.maxHistory" value="3" />
<!-- 格式化日志 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level %thread %logger %msg%n"/>
<!--输出到文件-->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志类型为info时,输出到配置好的文件 -->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
<!-- The FILE and ASYNC appenders are here as examples for a production configuration -->
<!--
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<charset>utf-8</charset>
<Pattern>%d %-5level [%thread] %logger{0}: %msg%n</Pattern>
</encoder>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>512</queueSize>
<appender-ref ref="FILE"/>
</appender>
-->
<logger name="javax.activation" level="WARN"/>
<logger name="javax.mail" level="WARN"/>
<logger name="javax.xml.bind" level="WARN"/>
<logger name="ch.qos.logback" level="WARN"/>
<logger name="com.codahale.metrics" level="WARN"/>
<logger name="com.ryantenney" level="WARN"/>
<logger name="com.sun" level="WARN"/>
<logger name="com.zaxxer" level="WARN"/>
<logger name="io.undertow" level="WARN"/>
<logger name="io.undertow.websockets.jsr" level="ERROR"/>
<logger name="org.apache" level="WARN"/>
<logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/>
<logger name="org.bson" level="WARN"/>
<logger name="org.hibernate.validator" level="WARN"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/>
<logger name="org.springframework" level="INFO"/>
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springframework.security" level="INFO"/>
<logger name="org.springframework.cache" level="INFO"/>
<logger name="org.thymeleaf" level="WARN"/>
<logger name="org.xnio" level="WARN"/>
<logger name="springfox" level="WARN"/>
<logger name="sun.rmi" level="WARN"/>
<logger name="liquibase" level="WARN"/>
<logger name="LiquibaseSchemaResolver" level="INFO"/>
<logger name="sun.rmi.transport" level="WARN"/>
<logger name="com.netflix.turbine.monitor.cluster" level="INFO"/>
<logger name="com.netflix.turbine.discovery" level="WARN"/>
<logger name="org.reflections.Reflections" level="ERROR"/>
<!-- https://logback.qos.ch/manual/configuration.html#shutdownHook and https://jira.qos.ch/browse/LOGBACK-1090 -->
<shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
</configuration>
Note
PatternLayout包含的所有有效的格式
%c 输出logger名称
%C 输出类名
%d{HH:mm:ss.SSS} 表示输出到毫秒的时间
%t 输出当前线程名称
%-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
%logger 输出logger名称,因为Root Logger没有名称,所以没有输出
%msg 日志文本
%n 换行
其他常用的占位符有:
%F 输出所在的类文件名,如Log4j2Test.java
%L 输出行号
%M或%method 输出所在方法名
%l 输出完整的错误位置, 包括类名、方法名、文件名、行数
%p 该条日志的优先级
%replace{pattern}{regex}{substitution} 将pattern的输出结果pattern按照正则表达式regex替换成substitution
31、事务和多数据源
@EnableTransactionManagement//开启事务管理
@Transactional
//@Transactional( value = "changeStateOfNewNetworkTransactionManager" )
@Override
public R<String> changeStateOfNewNetwork(String provinceName, String deviceName, String ipAddr, String lifeState, String lockState, String datasource, String busiType, String orderId) throws Exception {
有时,在一个项目中会用到多数据源,此时可以使用苞米豆的dynamic-datasource-spring-boot-starter:
首先,引入jar包:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
然后,在Springboot的application.yml中进行配置:
spring:
datasource:
url: jdbc:mysql://localhost:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
dynamic:
primary: master
datasource:
master:
url: jdbc:mysql://localhost:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
sub:
url: jdbc:mysql://localhost:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root1
password: root1
其中配置了两个数据源,master与sub,其中选择master作为默认数据源(对应primary配置);
若想使用sub作为部分代码的数据源,可在ServiceImpl做如下配置:
@DS("sub")
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
在使用@DS注解时,有如下注意事项:
不能使用事务,否则数据源不会切换,使用的还是第一次加载的数据源;
第一次加载数据源之后,第二次、第三次…操作其它数据源,如果数据源不存在,使用的还是第一次加载的数据源;数据源名称不要包含下划线,否则不能切换。
32、logback-spring.xml
logging:
#日志级别
level:
ROOT: debug
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<contextName>logs</contextName>
<!-- 日志位置 -->
<property name="log.path" value="./logs/" />
<!-- 日志保留时长 -->
<property name="log.maxHistory" value="15" />
<!-- 格式化日志 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level %thread %logger %msg%n"/>
<!--输出到文件-->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/info/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<MaxHistory>${log.maxHistory}</MaxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志类型为info时,输出到配置好的文件 -->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
<!-- The FILE and ASYNC appenders are here as examples for a production configuration -->
<!--
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<charset>utf-8</charset>
<Pattern>%d %-5level [%thread] %logger{0}: %msg%n</Pattern>
</encoder>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>512</queueSize>
<appender-ref ref="FILE"/>
</appender>
-->
<logger name="javax.activation" level="WARN"/>
<logger name="javax.mail" level="WARN"/>
<logger name="javax.xml.bind" level="WARN"/>
<logger name="ch.qos.logback" level="WARN"/>
<logger name="com.codahale.metrics" level="WARN"/>
<logger name="com.ryantenney" level="WARN"/>
<logger name="com.sun" level="WARN"/>
<logger name="com.zaxxer" level="WARN"/>
<logger name="io.undertow" level="WARN"/>
<logger name="io.undertow.websockets.jsr" level="ERROR"/>
<logger name="org.apache" level="WARN"/>
<logger name="org.apache.catalina.startup.DigesterFactory" level="OFF"/>
<logger name="org.bson" level="WARN"/>
<logger name="org.hibernate.validator" level="WARN"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="org.hibernate.ejb.HibernatePersistence" level="OFF"/>
<logger name="org.springframework" level="INFO"/>
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springframework.security" level="INFO"/>
<logger name="org.springframework.cache" level="INFO"/>
<logger name="org.thymeleaf" level="WARN"/>
<logger name="org.xnio" level="WARN"/>
<logger name="springfox" level="WARN"/>
<logger name="sun.rmi" level="WARN"/>
<logger name="liquibase" level="WARN"/>
<logger name="LiquibaseSchemaResolver" level="INFO"/>
<logger name="sun.rmi.transport" level="WARN"/>
<logger name="com.netflix.turbine.monitor.cluster" level="INFO"/>
<logger name="com.netflix.turbine.discovery" level="WARN"/>
<logger name="org.reflections.Reflections" level="ERROR"/>
<!-- https://logback.qos.ch/manual/configuration.html#shutdownHook and https://jira.qos.ch/browse/LOGBACK-1090 -->
<shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
</configuration>
33、maven带依赖打包
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
33、自动生成
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD Ctsi MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/ctsi-mybatis-generator-config_1_0.dtd">
<!--<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">-->
<generatorConfiguration>
<context id="ctsibiyii" targetRuntime="com.ctsi.biyi.generator.plugins.IntrospectedTableBiyiMyBatis3Impl">
<property name="databaseDialect" value="mysql"/>
<property name="dataAccess" value="mybatis"/>
<property name="useES" value="false"/>
<property name="javaFileEncoding" value="UTF-8"/>
<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin" />
<plugin type="com.ctsi.biyi.generator.plugins.SerializableBiyiPlugin" />
<plugin type="com.ctsi.biyi.generator.plugins.MapperAnnotationBiyiPlugin" />
<plugin type="com.ctsi.biyi.generator.plugins.ExampleBiyiPlugin" />
<plugin type="com.ctsi.biyi.generator.plugins.ClassCommentPlugin" />
<plugin type="com.ctsi.biyi.generator.plugins.ServicePlugin" >
<property name="importPackage" value="com.ctsi.g5c.ems"/>
<property name="targetPackage" value="com.ctsi.g5c.ems"/>
<property name="targetProject" value="src/main/java"/>
<!-- <property name="targetWebProject" value="..ctsibiyiiweb"/> -->
</plugin>
<plugin type="com.ctsi.biyi.generator.plugins.UnitSelectPlugin" >
<property name="importPackage" value="com.ctsi.g5c.ems"/>
<property name="targetPackage" value="com.ctsi.g5c.ems"/>
<property name="targetProject" value="src/main/java"/>
</plugin>
<commentGenerator type="com.ctsi.biyi.generator.MyCommentGenerator">
</commentGenerator>
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://122.51.251.37/5gc_cycle_flow?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true"
userId="cycleUser"
password="cycle@##OID#3">
<property name="nullCatalogMeansCurrent" value="true" />
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<javaModelGenerator targetPackage="com.ctsi.g5c.ems.domain" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<sqlMapGenerator targetPackage="com.ctsi.g5c.ems.xml" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<javaClientGenerator type="ANNOTATEDMAPPER" targetPackage="com.ctsi.g5c.ems.repository" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- <table schema="pg5gc_control_sc" tableName="cm_device">-->
<!-- <property name="cmDevice" value="false"/>-->
<!-- <!–<generatedKey column="id" sqlStatement="mysql" identity="true" />–>-->
<!-- </table>-->
</context>
</generatorConfiguration>
34、gitignore失效
问题:
当使用IDEA提交项目数据到git时, 即使配置了提交忽略文件.gitignore,也无法生效,提交文件中会出现杂乱配置文件,不知道你自己所更改了哪些项目位置,查看比较麻烦
.gitignore文件
原因:
.gitignore只能忽略未被track的文件,而git本地缓存。如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。
解决:
解决方法就是先把本地缓存删除(改变成未track状态),然后再提交。使用以下几个命令即可快速解决
注意:以下命令需要在你项目中右键点击 Git Bash Here进行命令窗口输入
git rm -r --cached .
git add .
git commit -m 'update .gitignore'