杂项随记
Posted luboyan2524
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杂项随记相关的知识,希望对你有一定的参考价值。
1. System.out.printf
-
System.out.printf("--%s--%s--", arg1, arg2); 可以按指定格式输出参数,%s为占位符,后面跟相同个数个参数
2. try-with-resources
-
jdk1.7对 try-catch-finally 释放资源作了优化,只要是实现了java.lang.AutoCloseable接口的资源(java.io.closeable接口继承了AutoCloseable),都可以自动释放,而不用再写finally释放语句
//try(){}直接在()中定义需要释放的资源,在{}中编写逻辑代码
try(FileReader fr = new FileReader("fr.txt");
FileWriter fw = new FileWriter("fw.txt")){
char[] chars = new char[1024];
int len;
while ((len = fr.read(chars)) != -1){
fw.write(chars,0,len);
}
} catch (IOException e){
e.printStackTrace();
}
3. 日志输出问题
-
当出现Failed to load class "org.slf4j.impl.StaticLoggerBinder"错误时,需要导入slf4j-nop.jar、 slf4j-simple.jar、 slf4j-log4j12.jar、slf4j-jdk14.jar 或者 logback-classic.jar 其中的一个。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency> -
springboot从1.4开始只支持log4j2,log4j2的配置文件为log4j2.xml
-
依赖导入,需要先排除spring-boot-starter-logging,再引入spring-boot-starter-log4j2
-
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<exclusions>
<!--排除logging-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--配置log4j2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
</dependencies>
-
配置文件log4j2.xml
-
记录日志
private static final Logger logger = LoggerFactory.getLogger(Xxxx.class);
4. 导入项目的语言版本问题
-
本地新建项目的编译环境都是jdk1.8,但对于导入的项目,可能会出现其他language level,彻底解决办法为pom.xml中添加jdk1.8插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
5. 集合相关
-
TreeMap
TreeMap中存入的自定义类对象元素必须实现Comparable接口,或者创建TreeMap对象时构造器传入比较器,否则tm.put()直接报错。jdk对String类型、Integer类型等默认实现了Comparable接口
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
-
Collections工具类常用方法
replaceAll(List<T> list, T oldVal, T newVal) //将列表中所有出现的指定值替换为另一个值。
reverse(List<?> list) //反转指定列表中元素的顺序。
shuffle(List<?> list) //将指定列表随机排序。
sort(List<T> list, Comparator<? super T> c) //根据指定的比较器对列表排序,默认自然排序。
-
Arrays工具类常用方法
asList(T... a) //返回由指定数组支持的固定大小的列表。
sort(T[] a, Comparator<? super T> c) //根据指定的比较器对对象数组排序,默认自然排序。
static <T> Stream<T> stream(T[] array) //返回顺序Stream与指定的数组作为源。
-
并发修改异常
对于List集合,迭代过程中,可以修改元素set,不能增删元素,增删会导致modcount++
Iterator<String> it = list.iterator();
while (it.hasNext()){
String element = it.next();
if(element.equals("hello")){
list.add("yangxun"); //迭代过程中增加元素会导致并发修改异常
list.remove(element);//迭代过程中删除元素会导致并发修改异常
list.set(list.indexOf(element),"yangxun");//迭代过程可以修改元素
}
}
-
HashSet存储元素分析
调用对象hashCode()方法获取对象的哈希值
根据哈希值计算对象在哈希表上的存储位置
如果该位置还未添加元素,就直接添加;如果已存在元素,按下述步骤
把对象和已存在的元素逐个比较哈希值,如果没有重复的哈希值,就直接添加
如果存在重复的哈希值,则继续调用equals()方法比较内容,如果内容不相同,则添加,如果内容相同,则不添加
-
ConcurrentHashMap的锁分段技术
HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
6. Lambda表达式和方法引用
-
Lambda表达式(调用接口方法处理参数)
-
Lambda表达式的使用前提
-
有一个接口
-
接口中有且仅有一个抽象方法
-
在另一个方法中调用接口方法
-
-
Lambda表达式的省略规则
-
参数类型可以省略。有多个参数的情况下,全部都要
-
如果参数有且仅有一个,那么小括号可以省略
-
如果代码块的语句只有一条,可以省略大括号和分号,和return关键字
//有且仅有一个方法的接口
public interface Addable {
int add(int x, int y);
}
//调用接口方法
public class LambdaDemo {
public static void main(String[] args) {
useEatable((1,2) -> add(1,2));
}
}
//创建线程
Thread thread = new Thread(() -> {
System.out.print(“利用Lambda创建线程”);
});
Set set = new TreeSet<Student>((s1, s2) -> s1.getAge() - s2.getAge())
-
方法引用(Lambda调用接口方法中的逻辑正好为调用另一个类的方法)
方法引用是Lambda的孪生兄弟,方法引用是在Lambda的基础上使用的,当接口中仅有的一个方法【作用正好和其他类的方法相同】,则可以引用其他类的方法。方法引用符为::
-
静态方法引用 类名::静态方法 Integer::parseInt
-
成员方法引用 类名::成员方法 String::substring
-
构造器引用 类名::new Student::new
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
//接口中仅有的一个方法的作用是返回一个Student实例对象,和Student类的构造作用一样
public interface StudentBuilder {
Student build(String name,int age);
}
//方法引用
public class StudentDemo {
public static void main(String[] args) {
//Lambda简化写法
useStudentBuilder((name,age) -> new Student(name,age));
//引用构造器
useStudentBuilder(Student::new);
}
}
7. 逻辑(没有变量就新建变量)
-
页面:查询显示页面所有的元素 ——》2. 鼠标点击,触发元素状态改变 ——》3. 元素没有变量,则新建变量记录元素状态的变化
-
代码:业务代码 ——》2. 业务逻辑改变 ——》3. 建立变量记录业务逻辑状态的改变,两个状态用true/false标记状态;两个以上(n)状态用(i % n)标记状态
8. 接口开发规范
-
8.1 Api请求及响应规范
为了严格按照接口进行开发,提高效率,对请求及响应格式进行规范化。
1、get 请求时,采用key/value格式请求,SpringMVC可采用基本类型的变量接收,也可以采用对象接收。
2、Post请求时,可以提交form表单数据(application/x-www-form-urlencoded)和Json数据(Content-Type=application/json),文件等多部件类型(multipart/form-data)三种数据格式,SpringMVC接收Json数据使用@RequestBody注解解析请求的json数据。
4、响应结果统一信息为:是否成功、操作代码、提示信息及自定义数据。
5、响应结果统一格式为json。
-
8.2 Api定义约束
Api定义使用SpringMVC来完成,由于此接口后期将作为微服务远程调用使用,在定义接口时有如下限制:
1、@PathVariable 统一指定参数名称,如:@PathVariable("id")
2、@RequestParam统一指定参数名称,如:@RequestParam("id")
9. sql语句书写规则
-
确定子查询,求出位置条件
-
当子查询的结果为单行单列, 可以作为where 字句的拼接条件
-
当子查询的结果为多行单列, 可以作为 IN() 拼接条件
-
当子查询的结果是多行多列的, 可以作为一张虚拟表进行复合查询
-
-
罗列表名
-
拼接条件(确定是否需要使用外连接:是否需要显示某表未匹配的记录——1. 主表中未参与副表外键约束的记录;2. 副表中外键字段为null的记录)
-
罗列笛卡尔积根据条件筛选后需要显示的字段
10. 通用响应结果
-
通用状态码枚举类
public enum CommonCode {
/**操作成功*/
SUCCESS(10000,true,"操作成功!"),
/**操作失败*/
FAIL(11111,false,"操作失败!"),
/**权限不足*/
UNAUTHENTICATED(10002,false,"权限不足!"),
/**非法参数*/
INVALID_PARAM(10003,false,"非法参数!"),
/**系统错误*/
SERVER_ERROR(10004,false,"抱歉,系统繁忙!");
?
int code;
boolean success;
String message;
?
CommonCode(int code, boolean success, String message) {
this.code = code;
this.success = success;
this.message = message;
}
public int getCode() {
return code;
}
public boolean isSuccess() {
return success;
}
public String getMessage() {
return message;
}
}
-
响应结果,默认操作成功,无返回信息,可自行扩展
public class ResponseResult {
int code = 10000;
boolean success = true;
String message;
?
public ResponseResult() {
}
?
public ResponseResult(CommonCode commonCode) {
this.code = commonCode.getCode();
this.success = commonCode.isSuccess();
this.message = commonCode.getMessage();
}
}
-
自定义扩展的分页查询响应结果
public class QueryPageResult<T> extends ResponseResult {
/**当前页码*/
int pageNum;
/**总记录数*/
long totalCount;
/**每页大小*/
int pageSize;
/**总页数*/
int totalPage;
/**记录*/
List<T> pageList;
?
//setter/getter方法略。。。
}
-
自定义异常响应结果
//自定义异常类
public class CustomException extends RuntimeException {
/**错误状态吗*/
CommonCode commonCode;
public CustomException(CommonCode commonCode){
this.commonCode = commonCode;
}
public CommonCode getCommonCode() {
return commonCode;
}
}
?
//统一定义异常抛出类
public class ExceptionCast {
public static void cast(CommonCode commonCode){
throw new CustomException(commonCode);
}
}
?
//自定义异常捕获类
11. 输出html页面内容
由于是要输出html页面内容,所以不能用RestController注解,否则输出json数据,而应该直接用Response将页面内容输出
12. 链表、树状结构查询
数据类型递归定义:直接定义节点,节点中嵌套子节点(或者子节点数组),
Node extends TargetModel(Node、List<Node>)
-
树形结构的sql查询语句
SELECT
a.id AS one_id,
a.pname AS one_pname,
b.id AS two_id,
b.pname AS two_pname,
c.id AS three_id,
c.pname AS three_pname
FROM
teachplan a
LEFT JOIN teachplan b
ON a.id = b.parentid
LEFT JOIN teachplan c
ON b.id = c.parentid
WHERE a.parentid = 0 ;
13. Mapper.xml异常
Mybatis报 "There is no getter for property named ‘xxxx‘ in ‘class java.lang.String‘",解决方法
<select id="selectList" parameterType="java.lang.String" resultMap="teachplanMap">
SELECT
*
FROM
teachplan a
WHERE a.parentid = 0
<if test="courseId != null and courseId != ‘‘">
and a.courseid = #{courseId}
</if>
</select>
将sql语句中的courseId改为_parameter传参
14. Spring框架常用工具类
15. 页面获取跳转url传参(&name=)
//todo 获取静态页面跳转传参的工具
function getQueryString(name){
let reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
let r = window.location.search.substr(1).match(reg);
if(r!=null)return unescape(r[2]); return null;
}
?
//调用方法
var name = getQueryString("name");
16. commons.io#IOUtils、FileUtils、FileNameUtils、FileFilterUtils
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
-
FileUtils.copyDirectoy():拷贝目录,可以用过滤器对文件进行过滤
File srcDir = new File("E:\IdeaProjects\ssm\srcDir");
File destDir = new File("E:\IdeaProjects\ssm\destDir");
IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
//可以接多个过滤器
IOFileFilter fileFilters = FileFilterUtils.and(txtSuffixFilter);
FileUtils.copyDirectory(srcDir,destDir,fileFilters);
-
FileUtils.copyFile(File srcFile, File destFile):拷贝文件
-
FileUtils.copyFileToDirectory(File srcFile, File destDir):拷贝文件到目标目录
-
FileUtils.copyInputStreamToFile(InputStream source, File destination):将一个输入流中的内容拷贝到目标文件
-
IOUtils.copy(InputStream input, OutputStream output):拷贝字节流
-
IOUtils.copy(InputStream input, Writer output, String encoding):拷贝字符流
-
IOUtils.copyLarge(InputStream input, OutputStream output):用于拷贝超过2G的流
-
List<String> IOUtils.readLines(Reader input):按行读取输入流到字符串集合
-
IOUtils.toString(Reader input):读取输入流为字符串
-
IOUtils.write(String data, Writer output):将字符串写为输出流
17. 发送消息内容用字符串
Map msgMap = new HashMap<>();
msgMap.put("pageId",pageId);
String msg = JSON.toJSONString(msgMap);
String siteId = cmsPage.getSiteId();
rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_POSTPAGE,siteId,msg);
18. pagehelper-spring-boot-starter
nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration.
Cause: com.github.pagehelper.PageException:java.lang.ClassNotFoundException: mysql
原因是:配置分页插件数据库不在是dialect
,而是helperDialect
,并且支持自动检测当前的数据库链接,因此不用配置也是 ok 的啦,配置为pagehelper.helperDialect:mysql。
19. springMVC配置fastJson
<!--使用fastjson替换springMVC默认集成的jackson转换器-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json"/>
<property name="features">
<list>
<value>WriteMapNullValue</value>
<value>WriteDateUseDateFormat</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
20. js中日期格式化工具
Date.prototype.Format = function(fmt)
{ //author: meizz
var o = {
"M+" : this.getMonth()+1, //月份
"d+" : this.getDate(), //日
"h+" : this.getHours(), //小时
"m+" : this.getMinutes(), //分
"s+" : this.getSeconds(), //秒
"q+" : Math.floor((this.getMonth()+3)/3), //季度
"S" : this.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt))
fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
for(var k in o)
if(new RegExp("("+ k +")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
return fmt;
}
?
//调用方法
var time1 = new Date().Format("yyyy-MM-dd hh:mm:ss"); //2019-09-24 15:30:45
var time2 = new Date().Format("yyyy-MM-dd"); //2019-09-24
21. nginx配置反向代理
#定义被代理服务
upstream static_server_pool {
server 127.0.0.1:91 weight=10;
}
?
server {
listen 80; #主站端口
server_name www.xuecheng.com; #主站域名
ssi on; #开启SSI服务端嵌入功能
ssi_silent_errors on;
location / { #门户主站的物理路径
alias E:/WebstormProjects/xcEduUI/xc-ui-pc-static-portal/;
index index.html;
}
#访问路径为www.xuecheng.com/course/detail/....时,跳转至被代理服务路径static_server_pool/course/detail/....
location /course/detail/ {
proxy_pass http://static_server_pool;
}
}
?
server {
listener 91;
server_name localhost;
location /course/detail { #被代理服务访问路径的物理路径
alias E:/WebstormProjects/xcEduUI/xc-ui-pc-static-portal/course/detail/;
}
}
22. 通用mapper实现多字段排序
// 测试通用mapper先按category_id1字段升序,再按count_date降序进行排序查询
23. 通用mapper非单表操作属性映射
对于非单表操作查询结果和实体类属性匹配的情况,或者和自定义实体类属性匹配的情况,必须通过取别名的方式,手动指定表字段与非表对应实体类属性名的映射关系
-- 通过别名,指定tb_order和tb_orderitem的查询结果字段与CategoryReport的属性映射
SELECT
oi.`category_id1` AS categoryId1,
oi.`category_id2` AS categoryId2,
oi.`category_id3` AS categoryId3,
DATE_FORMAT(o.`pay_time`, ‘%Y-%m-%d‘) AS countDate,
SUM(num) AS num,
SUM(o.`pay_money`) AS money
FROM
tb_order_item AS oi,
tb_order AS o
WHERE o.`id` = oi.`order_id`
AND o.`pay_status` = ‘1‘
AND o.`is_delete` = ‘0‘
AND DATE_FORMAT(o.`pay_time`, ‘%Y-%m-%d‘) = ‘2019-08-23‘
GROUP BY oi.`category_id3`
-- 通过别名,指定tb_category_report和v_category的查询结果字段对应的属性名
SELECT
category_id1 AS categoryId1,
NAME AS categoryName,
count_date AS countDate,
SUM(num) AS num,
SUM(money) AS money
FROM
tb_category_report cr,
v_category c
WHERE count_date >= ‘2019-08-23‘ -- 对于mysql中的Date类型数据,可以传入Date类型数据操作
AND count_date <= ‘2019-08-24‘ -- 也可以传入‘yyyy-MM-dd’标准格式的日期字符串操作
AND category_id1 = c.id
GROUP BY category_id1
24. Hutool Java工具包
<!--Hutool Java工具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.7</version>
</dependency>
以上是关于杂项随记的主要内容,如果未能解决你的问题,请参考以下文章