System.out.printf("--%s--%s--", arg1, arg2); 可以按指定格式输出参数,%s为占位符,后面跟相同个数个参数
jdk1.7对 try-catch-finally 释放资源作了优化,只要是实现了java.lang.AutoCloseable接口的资源(java.io.closeable接口继承了AutoCloseable),都可以自动释放,而不用再写finally释放语句
1 //try(){}直接在()中定义需要释放的资源,在{}中编写逻辑代码 2 try(FileReader fr = new FileReader("fr.txt"); 3 FileWriter fw = new FileWriter("fw.txt")){ 4 char[] chars = new char[1024]; 5 int len; 6 while ((len = fr.read(chars)) != -1){ 7 fw.write(chars,0,len); 8 } 9 } catch (IOException e){ 10 e.printStackTrace(); 11 }
当出现Failed to load class "org.slf4j.impl.StaticLoggerBinder"错误时,需要导入slf4j-nop.jar、 slf4j-simple.jar、 slf4j-log4j12.jar、slf4j-jdk14.jar 或者 logback-classic.jar 其中的一个。
1 <dependency> 2 <groupId>org.slf4j</groupId> 3 <artifactId>slf4j-log4j12</artifactId> 4 <version>1.7.25</version> 5 </dependency>
springboot从1.4开始只支持log4j2,log4j2的配置文件为log4j2.xml
依赖导入,需要先排除spring-boot-starter-logging,再引入spring-boot-starter-log4j2
1 <dependencies> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-amqp</artifactId> 5 <exclusions> 6 <!--排除logging--> 7 <exclusion> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-logging</artifactId> 10 </exclusion> 11 </exclusions> 12 </dependency> 13 <!--配置log4j2--> 14 <dependency> 15 <groupId>org.springframework.boot</groupId> 16 <artifactId>spring-boot-starter-log4j2</artifactId> 17 </dependency> 18 </dependencies>
配置文件log4j2.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> 3 <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出--> 4 <!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数--> 5 <configuration status="INFO" monitorInterval="30"> 6 <!--先定义所有的appender--> 7 <appenders> 8 <!--这个输出控制台的配置--> 9 <console name="Console" target="SYSTEM_OUT"> 10 <!--输出日志的格式--> 11 <PatternLayout pattern="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/> 12 </console> 13 14 <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用--> 15 <File name="Test" fileName="log/test.log" append="false"> 16 <PatternLayout pattern="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/> 17 </File> 18 19 <!--设置日志文件会滚更新--> 20 <RollingFile name="RollingFileInfo" fileName="log/log.log" filePattern="log/log.log.%d{yyyy-MM-dd}"> 21 <!-- 只接受level=INFO以上的日志 --> 22 <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> 23 <PatternLayout pattern="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/> 24 <Policies> 25 <TimeBasedTriggeringPolicy modulate="true" interval="1"/> 26 <SizeBasedTriggeringPolicy/> 27 </Policies> 28 </RollingFile> 29 30 <RollingFile name="RollingFileError" fileName="log/error.log" filePattern="log/error.log.%d{yyyy-MM-dd}"> 31 <!-- 只接受level=WARN以上的日志 --> 32 <Filters> 33 <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY" /> 34 </Filters> 35 <PatternLayout pattern="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/> 36 <Policies> 37 <TimeBasedTriggeringPolicy modulate="true" interval="1"/> 38 <SizeBasedTriggeringPolicy/> 39 </Policies> 40 </RollingFile> 41 42 </appenders> 43 44 <!--然后定义logger,只有定义了logger并引入了appender,appender才会生效--> 45 <loggers> 46 <!--过滤掉spring和mybatis的一些无用的DEBUG信息--> 47 <logger name="org.springframework" level="INFO"></logger> 48 <logger name="org.mybatis" level="INFO"></logger> 49 <root level="all"> 50 <appender-ref ref="Console"/> 51 <appender-ref ref="Test"/> 52 <appender-ref ref="RollingFileInfo"/> 53 <appender-ref ref="RollingFileError"/> 54 </root> 55 </loggers> 56 </configuration>
记录日志
private static final Logger logger = LoggerFactory.getLogger(Xxxx.class);
本地新建项目的编译环境都是jdk1.8,但对于导入的项目,可能会出现其他language level,彻底解决办法为pom.xml中添加jdk1.8插件
1 <plugin> 2 <groupId>org.apache.maven.plugins</groupId> 3 <artifactId>maven-compiler-plugin</artifactId> 4 <version>3.2</version> 5 <configuration> 6 <source>1.8</source> 7 <target>1.8</target> 8 <encoding>UTF-8</encoding> 9 </configuration> 10 </plugin>
TreeMap
TreeMap中存入的自定义类对象元素必须实现Comparable接口,或者创建TreeMap对象时构造器传入比较器,否则tm.put()直接报错。jdk对String类型、Integer类型等默认实现了Comparable接口
1 TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() { 2 @Override 3 public int compare(Student o1, Student o2) { 4 int num = o1.getAge() - o2.getAge(); 5 return num == 0 ? o1.getName().compareTo(o2.getName()) : num; 6 } 7 })
Collections工具类常用方法
1 replaceAll(List<T> list, T oldVal, T newVal) //将列表中所有出现的指定值替换为另一个值。 2 reverse(List<?> list) //反转指定列表中元素的顺序。 3 shuffle(List<?> list) //将指定列表随机排序。 4 sort(List<T> list, Comparator<? super T> c) //根据指定的比较器对列表排序,默认自然排序。
Arrays工具类常用方法
1 asList(T... a) //返回由指定数组支持的固定大小的列表。 2 sort(T[] a, Comparator<? super T> c) //根据指定的比较器对对象数组排序,默认自然排序。 3 static <T> Stream<T> stream(T[] array) //返回顺序Stream与指定的数组作为源。
并发修改异常
对于List集合,迭代过程中,可以修改元素set,不能增删元素,增删会导致modcount++
1 Iterator<String> it = list.iterator(); 2 while (it.hasNext()){ 3 String element = it.next(); 4 if(element.equals("hello")){ 5 list.add("yangxun"); //迭代过程中增加元素会导致并发修改异常 6 list.remove(element);//迭代过程中删除元素会导致并发修改异常 7 list.set(list.indexOf(element),"yangxun");//迭代过程可以修改元素 8 } 9 }
HashSet存储元素分析
调用对象hashCode()方法获取对象的哈希值
根据哈希值计算对象在哈希表上的存储位置
如果该位置还未添加元素,就直接添加;如果已存在元素,按下述步骤
把对象和已存在的元素逐个比较哈希值,如果没有重复的哈希值,就直接添加
如果存在重复的哈希值,则继续调用equals()方法比较内容,如果内容不相同,则添加,如果内容相同,则不添加
ConcurrentHashMap的锁分段技术
HashTable容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
Lambda表达式(调用接口方法处理参数)
Lambda表达式的使用前提
有一个接口
接口中有且仅有一个抽象方法
在另一个方法中调用接口方法
Lambda表达式的省略规则
参数类型可以省略。有多个参数的情况下,全部都要
如果参数有且仅有一个,那么小括号可以省略
如果代码块的语句只有一条,可以省略大括号和分号,和return关键字
1 //有且仅有一个方法的接口 2 public interface Addable { 3 int add(int x, int y); 4 } 5 //调用接口方法 6 public class LambdaDemo { 7 public static void main(String[] args) { 8 useEatable((1,2) -> add(1,2)); 9 } 10 } 11 //创建线程 12 Thread thread = new Thread(() -> { 13 System.out.print(“利用Lambda创建线程”); 14 }); 15 Set set = new TreeSet<Student>((s1, s2) -> s1.getAge() - s2.getAge())
方法引用(Lambda调用接口方法中的逻辑正好为调用另一个类的方法)
方法引用是Lambda的孪生兄弟,方法引用是在Lambda的基础上使用的,当接口中仅有的一个方法【作用正好和其他类的方法相同】,则可以引用其他类的方法。方法引用符为::
静态方法引用 类名::静态方法 Integer::parseInt
成员方法引用 类名::成员方法 String::substring
构造器引用 类名::new Student::new
1 2 public class Student { 3 private String name; 4 private int age; 5 public Student() { 6 } 7 public Student(String name, int age) { 8 this.name = name; 9 this.age = age; 10 } 11 } 12 //接口中仅有的一个方法的作用是返回一个Student实例对象,和Student类的构造作用一样 13 public interface StudentBuilder { 14 Student build(String name,int age); 15 } 16 //方法引用 17 public class StudentDemo { 18 public static void main(String[] args) { 19 //Lambda简化写法 20 useStudentBuilder((name,age) -> new Student(name,age)); 21 //引用构造器 22 useStudentBuilder(Student::new); 23 } 24 }
页面:查询显示页面所有的元素 ——》2. 鼠标点击,触发元素状态改变 ——》3. 元素没有变量,则新建变量记录元素状态的变化
代码:业务代码 ——》2. 业务逻辑改变 ——》3. 建立变量记录业务逻辑状态的改变,两个状态用true/false标记状态;两个以上(n)状态用(i % n)标记状态
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")
确定子查询,求出位置条件
当子查询的结果为单行单列, 可以作为where 字句的拼接条件
当子查询的结果为多行单列, 可以作为 IN() 拼接条件
当子查询的结果是多行多列的, 可以作为一张虚拟表进行复合查询
罗列表名
拼接条件(确定是否需要使用外连接:是否需要显示某表未匹配的记录——1. 主表中未参与副表外键约束的记录;2. 副表中外键字段为null的记录)
罗列笛卡尔积根据条件筛选后需要显示的字段
通用状态码枚举类
1 public enum CommonCode { 2 /**操作成功*/ 3 SUCCESS(10000,true,"操作成功!"), 4 /**操作失败*/ 5 FAIL(11111,false,"操作失败!"), 6 /**权限不足*/ 7 UNAUTHENTICATED(10002,false,"权限不足!"), 8 /**非法参数*/ 9 INVALID_PARAM(10003,false,"非法参数!"), 10 /**系统错误*/ 11 SERVER_ERROR(10004,false,"抱歉,系统繁忙!"); 12 ? 13 int code; 14 boolean success; 15 String message; 16 ? 17 CommonCode(int code, boolean success, String message) { 18 this.code = code; 19 this.success = success; 20 this.message = message; 21 } 22 public int getCode() { 23 return code; 24 } 25 public boolean isSuccess() { 26 return success; 27 } 28 public String getMessage() { 29 return message; 30 } 31 }
响应结果,默认操作成功,无返回信息,可自行扩展
1 public class ResponseResult { 2 int code = 10000; 3 boolean success = true; 4 String message; 5 ? 6 public ResponseResult() { 7 } 8 ? 9 public ResponseResult(CommonCode commonCode) { 10 this.code = commonCode.getCode(); 11 this.success = commonCode.isSuccess(); 12 this.message = commonCode.getMessage(); 13 } 14 }
自定义扩展的分页查询响应结果
1 2 public class QueryPageResult<T> extends ResponseResult { 3 /**当前页码*/ 4 int pageNum; 5 /**总记录数*/ 6 long totalCount; 7 /**每页大小*/ 8 int pageSize; 9 /**总页数*/ 10 int totalPage; 11 /**记录*/ 12 List<T> pageList; 13 ? 14 //setter/getter方法略。。。 15 }
自定义异常响应结果
//自定义异常类 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); } } ? //自定义异常捕获类 @ControllerAdvice @ResponseBody public class ExceptionCatch { public static final Logger logger = LoggerFactory.getLogger(ExceptionCast.class); ? /**捕获所有的自定义异常,并响应前端ResponseResult*/ @ExceptionHandler(CustomException.class) public ResponseResult customException(CustomException customException){ //记录异常日志 logger.error("catch exception:{}",customException.getCommonCode().getMessage()); return new ResponseResult(customException.getCommonCode()); } ? /**捕获不可预知的系统异常,并响应前端ResponseResult*/ @ExceptionHandler(Exception.class) public ResponseResult exception(Exception exception){ //记录异常日志 logger.error("catch exception:{}",exception.getMessage()); //统一响应99999,系统繁忙异常 return new ResponseResult(CommonCode.SERVER_ERROR); } }
由于是要输出html页面内容,所以不能用RestController注解,否则输出json数据,而应该直接用Response将页面内容输出
1 @Controller 2 public class CmsPagePreviewController extends BaseController { 3 @Autowired 4 private PageService pageService; 5 ? 6 @GetMapping("/cms/preview/{pageId}") 7 public void preview(@PathVariable("pageId") String pageId) throws Exception { 8 //执行静态化 9 String pageHtml = pageService.getPageHtml(pageId); 10 //通过response将内容输出 11 ServletOutputStream outputStream = response.getOutputStream(); 12 outputStream.write(pageHtml.getBytes("utf-8")); 13 } 14 }
数据类型递归定义:直接定义节点,节点中嵌套子节点(或者子节点数组),
1 Node extends TargetModel(Node、List<Node>) 2 4 @Data 5 @ToString 6 public class TeachplanNode extends Teachplan { 7 List<TeachplanNode> children; 8 }
树形结构的sql查询语句
1 SELECT 2 a.id AS one_id, 3 a.pname AS one_pname, 4 b.id AS two_id, 5 b.pname AS two_pname, 6 c.id AS three_id, 7 c.pname AS three_pname 8 FROM 9 teachplan a 10 LEFT JOIN teachplan b 11 ON a.id = b.parentid 12 LEFT JOIN teachplan c 13 ON b.id = c.parentid 14 WHERE a.parentid = 0 ;
Mybatis报 "There is no getter for property named ‘xxxx‘ in ‘class java.lang.String‘",解决方法
1 <select id="selectList" parameterType="java.lang.String" resultMap="teachplanMap"> 2 SELECT 3 * 4 FROM 5 teachplan a 6 WHERE a.parentid = 0 7 <if test="courseId != null and courseId != ‘‘"> 8 and a.courseid = #{courseId} 9 </if> 10 </select>
将sql语句中的courseId改为_parameter传参
1 //todo 获取静态页面跳转传参的工具 2 function getQueryString(name){ 3 let reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); 4 let r = window.location.search.substr(1).match(reg); 5 if(r!=null)return unescape(r[2]); return null; 6 } 7 ? 8 //调用方法 9 var name = getQueryString("name");
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.3</version> </dependency>
FileUtils.copyDirectoy():拷贝目录,可以用过滤器对文件进行过滤
1 2 File srcDir = new File("E:\\IdeaProjects\\ssm\\srcDir"); 3 File destDir = new File("E:\\IdeaProjects\\ssm\\destDir"); 4 IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt"); 5 //可以接多个过滤器 6 IOFileFilter fileFilters = FileFilterUtils.and(txtSuffixFilter); 7 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):将字符串写为输出流
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);
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。
1 2 <!--使用fastjson替换springMVC默认集成的jackson转换器--> 3 <mvc:annotation-driven> 4 <mvc:message-converters register-defaults="true"> 5 <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"> 6 <property name="supportedMediaTypes" value="application/json"/> 7 <property name="features"> 8 <list> 9 <value>WriteMapNullValue</value> 10 <value>WriteDateUseDateFormat</value> 11 </list> 12 </property> 13 </bean> 14 </mvc:message-converters> 15 </mvc:annotation-driven>
1 Date.prototype.Format = function(fmt) 2 { //author: meizz 3 var o = { 4 "M+" : this.getMonth()+1, //月份 5 "d+" : this.getDate(), //日 6 "h+" : this.getHours(), //小时 7 "m+" : this.getMinutes(), //分 8 "s+" : this.getSeconds(), //秒 9 "q+" : Math.floor((this.getMonth()+3)/3), //季度 10 "S" : this.getMilliseconds() //毫秒 11 }; 12 if(/(y+)/.test(fmt)) 13 fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); 14 for(var k in o) 15 if(new RegExp("("+ k +")").test(fmt)) 16 fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length))); 17 return fmt; 18 } 19 ? 20 //调用方法 21 var time1 = new Date().Format("yyyy-MM-dd hh:mm:ss"); //2019-09-24 15:30:45 22 var time2 = new Date().Format("yyyy-MM-dd"); //2019-09-24
1 #定义被代理服务 2 upstream static_server_pool { 3 server 127.0.0.1:91 weight=10; 4 } 5 ? 6 server { 7 listen 80; #主站端口 8 server_name www.xuecheng.com; #主站域名 9 ssi on; #开启SSI服务端嵌入功能 10 ssi_silent_errors on; 11 location / { #门户主站的物理路径 12 alias E:/WebstormProjects/xcEduUI/xc-ui-pc-static-portal/; 13 index index.html; 14 } 15 16 #访问路径为www.xuecheng.com/course/detail/....时,跳转至被代理服务路径static_server_pool/course/detail/.... 17 location /course/detail/ { 18 proxy_pass http://static_server_pool; 19 } 20 } 21 ? 22 server { 23 listener 91; 24 server_name localhost; 25 26 location /course/detail { #被代理服务访问路径的物理路径 27 alias E:/WebstormProjects/xcEduUI/xc-ui-pc-static-portal/course/detail/; 28 } 29 }
1 // 测试通用mapper先按category_id1字段升序,再按count_date降序进行排序查询 2 @Test 3 public void testMultiClauseOrder(){ 4 Example example = new Example(CategoryReport.class); 5 example.orderBy("categoryId1").asc().orderBy("countDate").desc(); 6 List<CategoryReport> categoryReports = categoryReportMapper.selectByExample(example); 7 System.out.println(categoryReports); 8 }
对于非单表操作查询结果和实体类属性匹配的情况,或者和自定义实体类属性匹配的情况,必须通过取别名的方式,手动指定表字段与非表对应实体类属性名的映射关系
1 -- 通过别名,指定tb_order和tb_orderitem的查询结果字段与CategoryReport的属性映射 2 SELECT 3 oi.`category_id1` AS categoryId1, 4 oi.`category_id2` AS categoryId2, 5 oi.`category_id3` AS categoryId3, 6 DATE_FORMAT(o.`pay_time`, ‘%Y-%m-%d‘) AS countDate, 7 SUM(num) AS num, 8 SUM(o.`pay_money`) AS money 9 FROM 10 tb_order_item AS oi, 11 tb_order AS o 12 WHERE o.`id` = oi.`order_id` 13 AND o.`pay_status` = ‘1‘ 14 AND o.`is_delete` = ‘0‘ 15 AND DATE_FORMAT(o.`pay_time`, ‘%Y-%m-%d‘) = ‘2019-08-23‘ 16 GROUP BY oi.`category_id3` 17 -- 通过别名,指定tb_category_report和v_category的查询结果字段对应的属性名 18 SELECT 19 category_id1 AS categoryId1, 20 NAME AS categoryName, 21 count_date AS countDate, 22 SUM(num) AS num, 23 SUM(money) AS money 24 FROM 25 tb_category_report cr, 26 v_category c 27 WHERE count_date >= ‘2019-08-23‘ -- 对于mysql中的Date类型数据,可以传入Date类型数据操作 28 AND count_date <= ‘2019-08-24‘ -- 也可以传入‘yyyy-MM-dd’标准格式的日期字符串操作 29 AND category_id1 = c.id 30 GROUP BY category_id1
<!--Hutool Java工具包--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.5.7</version> </dependency>
原文:https://www.cnblogs.com/luboyan2524/p/11788597.html