理解原理,归纳总结,生成步骤,方便照搬

  • IDEA操作
      • IDEA常用操作
      • Git可视化操作(提交代码前先pull更新merge最新版本一下再push,保证提交的最终项目是最新)
    • IDEA中Git冲突的产生及解决方法
    • Idea如何查看本地自动保存的代码版本
  • 实战注意
    • 开发完后测试前后端交互响应速度
    • 内存问题
    • 空指针问题
    • Git的pull项目后与本地IDEA的JDK不一致以及maven错启默认配置问题
    • Mybaits-Plus的SQL ERR报错
    • Every derived table must have its own alias(sql语句错误解决方法)
    • limit注意事项
      • 空格和传参问题(postman)
    • 优化慢SQL语句
  • JAVA
    • Java中,String类型和包装类型作为参数传递时,是属于值传递还是引用传递呢?
    • Java语法
    • java默认访问权限
    • String的substring
    • 中文乱码问题
    • 单例模式
  • DateUtil工具类(Date,Calender,SimpleDateFormat)
    • 计算日期之间差值(年月日时分秒毫秒)
      • 前情提要
      • Java代码(基于SimpleDateFormat,计算任意符合日期格式的变量类型与当前时间差)
    • Date日期转化为Long类型
    • 获取当前Date日期的不同YMD格式String
    • Calender实现日期变化操作
      • Calender得到上月末后几天日期
      • Calender获得月份天数
    • Calender获取上月月份(YYYYMM)
  • StrUtil工具类(StringBuffer)
    • 字符串拼接方法
  • File文件操作
    • JAVA - 按行读取文件
    • JAVA - 将数据生成为TXT文件(PrintWriter)
      • JAVA流操作结束后为什么要关闭流
    • JAVA-文件删除
      • java file 跨盘符_File类——遍历盘符根目录查找文件报错 java.lang.NullPointerException.
  • SpringBoot
    • SpringBoot注解
      • 启动类位置注意事项(一定要注意文件结构)
      • @MapperScan
    • SpringBoot+MybatisPlus的MVC模板
    • SpringBoot定时任务
    • slf4j的简单用法以及与log4j的区别
  • Mybatis-Plus
    • Mybatis-Plus的自定义SQL操作(注解版)
      • mapper层固定[crud教程](https://www.runoob.com/sql/sql-syntax.html)
        • 批量操作
    • Mybatis_Plus的debug步骤
  • 实战总结
    • 乐观锁处理多线程“抢占”现象

IDEA操作

IDEA常用操作

IDEA常用快捷键
CTR+ALT+L:快速格式化代码。
CTR+左击:类名/方法名则直接进入对应类和方法。

右上角放大镜搜索,可以设定搜索范围


IDEA查看并修改编解码方式

Git可视化操作(提交代码前先pull更新merge最新版本一下再push,保证提交的最终项目是最新)

注意:pull的次数不要太多,防止将别人测试版pull下来,push的时候和正式版产生冲突。
尽量初始化项目pull一次,提交之前pull一次,最后push。
若是产生冲突就需要新开窗口pull下来最新的cv上自己的然后push。
pull后融合,改动的地方以工作区为主,其余地方以远程仓库为主,若本地和远程相差过大则冲突
IDEA的git操作教程
pull下来远程仓库
方法一

此处若是未配置用户名和密码会弹出输入框

方法二
或者直接用上述办法一直接pull下来对应的远程仓库,这样会直接配置连接上对应的远程仓库。(若未输入用户名密码则会弹出来对应输入框)
配置连接远程数据库


选中项目然后右键

方法三


log:分支状态可视化
git log:查看当前(HEAD指向)分支的所有(empty到HEAD)版本


检查一遍

最后push


方法三

最终若是push出问题直接force push

IDEA中Git冲突的产生及解决方法

IDEA中Git冲突的产生及解决方法
冲突产生的根本原因是:多方改动后的同一个文件的同一块区域的内容不同。
单一账号改动的同一区域内容不会冲突。
Git问题:1.push时候遇到错误,push失败
究其原因是为了保证head指向的代码同步为最新版本。

push失败的情况,是因为我们在push提交代码的时候,远程仓库已经发生变化了(远程head头指针与本地保存的远程head头指针指向不同),换句话说就是在这个期间(上一次拉取代码到本次提交代码),有其他人在我们之前提交了代码到我们想要推送的分支,导致远程仓库代码更新变化了。所以git拒绝了本次push。

Idea如何查看本地自动保存的代码版本


恢复历史数据

实战注意

层级调用,注意不要在触发层存在Dao层代码。
定时任务整理数据入表,接口触发提取定时任务整理的数据表,缩短响应时间。

开发完后测试前后端交互响应速度

尽量减少数据库链接次数,链接数据库CRUD数据花费的时间很多(不要在for和while中出现DAO层操作)。
定时任务整理数据入表,接口触发提取定时任务整理的数据表,缩短响应时间。

内存问题

程序中所有定义的变量都会占内存,注意若是批量插入list等需要暂存大量数据的操作考虑一下会不会爆内存(达到数据量后需要先插入然后list.clear一下)。
注意:记得最后list数组内可能剩余未达到数量标准的数据,判一下list.size()>0然后循环外再插入。
java8解惑之字符串常量池(实现原理、垃圾回收)
结论:因为常量池是放在堆中,所以他的回收和普通对象是一样的,没有其他特别的地方。

空指针问题

用list数组接收SQL返回的数据后,调用前先判断一下list是否为空,防止SQL未查询到数据。
如何优雅的判空
CollectionUtils.isEmpty()作用:判断参数null或者其size0
关于CollectionUtils.isEmpty()

if (CollectionUtils.isEmpty(regionCountList)) {logger.info("{}日增量数据为空", date);}

例如:

实体类中包装类初始化为null然后和数值或其他相加等操作导致空指针报错

Git的pull项目后与本地IDEA的JDK不一致以及maven错启默认配置问题

JDK修改为一致1.8版本。


maven改为自定义环境(setting以及仓库)

Mybaits-Plus的SQL ERR报错

查看mp提供的拼接后的SQL,若排除SQL语法错误而是SQL不完整的原因报错则必因为service层传参值为空导致的SQL拼接报错。
例如:每次insert前都先判断一下是否为空。

Every derived table must have its own alias(sql语句错误解决方法)

Every derived table must have its own alias(sql语句错误解决方法)
当SQL中用另一个select的结果集作为from表时,必须给结果集起别名。

limit注意事项

SQL中limit的用法
limit子句用于限制查询结果返回的数量,常用于分页查询
格式

select * from tableName limit i,n
# tableName:表名
# i:为查询结果的索引值(默认从0开始),当i=0时可省略i
# n:为查询结果返回的数量
# i与n之间使用英文逗号","隔开
limit n 等同于 limit 0,n

例子

# 查询10条数据,索引从0到9,第1条记录到第10条记录
select * from t_user limit 10;
select * from t_user limit 0,10;# 查询8条数据,索引从5到12,第6条记录到第13条记录
select * from t_user limit 5,8;

空格和传参问题(postman)

空格
普通文本格式中的空格,复制到SQL文本窗口或者程序开发/测试文本窗口,可能会出问题。
所以若是持续出现格式报错则删除重写。
传参
Json串的key:value中key值不能首字母大写,容易和Date,Long等java类冲突。

优化慢SQL语句

写完select语句在生产库执行一下,看一下执行时间,时间过长的话需要优化。
group by 可以节省select查询时间。
恶意order by导致数据库慢查询(除非有索引)

JAVA

Java中,String类型和包装类型作为参数传递时,是属于值传递还是引用传递呢?

包装类型属于引用传递但是传参后方法改变数值后不会影响原数值。
因为包装类的数值为final类型所以不可改变而是会直接新建一个包装类对象来接收新数值(可比较内存地址查看是否为新建对象)。
其余自定义对象的引用(指针:内存地址)传值则可以在实例方法中改变对象值,原值同时改变


Java中的参数传递:分为值传递和引用传递
但本质上,Java中只有值传递。引用传递,其实可以理解为传的是类似指针的东西。
值传递就是把基本变量的值拷贝一份,传递这个拷贝。引用传递则是传递的引用的地址,也就是该变量在内存空间的地址
值传递
只有基本数据类型采用值传递,特点是传递的是值的拷贝,传递完后两者就没有关系了。也就是说方法内和方法外的值互不相干
基本数据类型:

引用传递
指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。
传递的是一个拷贝,即副本。也就是说,对于一个参数传递,存在两个地址指向同一个内存空间。这里我们可以用内存分配示意图来体现
String类型传递
先说结论,String类型传递与基本数据类型的传递效果相似。
说明:
String类对象一旦创建,其内容不可更改:
String类的所有方法都不会改变String类对象内容,要改变String类对象的值就必须创建一个新的String对象。
也就是说,当进行参数传递时,如果方法内对String类对象的值进行了修改,那么实际上是创建了一个新的String类对象,然后让原来的变量指向它而已。但是这个“原来的变量”是一份拷贝副本,只是一开始创建的时候与主方法中的传递的值相同而已,现在改变之后,两者就毫无关系了。

Java语法

java语法记录
java对象new实例之后,实例bean对应的变量也会赋初值(数值类型0或对象类型null)。

String初始值:null
Double初始值:null
Long初始值:null
double初始值:0.0
long初始值:0

java默认访问权限

Java默认访问权限

String的substring

注意:substring(start,end)中索引不能越界,否则报错。
java.lang.StringIndexOutOfBoundsException: String index out of range

中文乱码问题

对unicode的编码与解码方式不一致。
一听就能懂字符集、ASCII、GBK、Unicode、UTF-8、字符编码、解码、乱码问题的讲解

单例模式

工具类
构造方法private
全都是静态方法
类名.静态方法(参数)实现功能

DateUtil工具类(Date,Calender,SimpleDateFormat)

计算日期之间差值(年月日时分秒毫秒)

注意:String可以作为任意类型转化为Date类型的中介
Object.toString()---->String–SimpleDateFormat.parse–>Date
Date–SimpleDateFormat.format–>String---->Object.parseObject(String)

前情提要

format时间格式
可带前导零的精确到毫秒的时间格式:yyyy-MM-dd HH:mm:ss.SSS:2022-09-28 16:19:08.338

注意:时间格式区分大小写
不要把月份的MM写为分钟mm
java中的的日期格式为:

yyyy-MM-dd HH:mm:ss:代表将时间转换为24小时制,例: 2020-01-07 13:21:55
yyyy-MM-dd hh:mm:ss: 代表将时间转换为12小时制,例: 2020-01-07 03:24:21

oracle中( to_char())的日期格式为(不区分大小写):
oracle日期格式转换 to_date(),to_char()
oracle 日期格式
(1)to_date(“要转换的字符串”,“转换的格式”) 两个参数的格式必须匹配,否则会报错。
是将字符串转化为日期(DATE)格式,而且转化之后的格式与orcal系统日期参数有关,
(2)to_char(日期,“转换格式” ) 即把给定的日期按照“转换格式”转换。
是将日期格式转化为字符串格式
Qracle中不区分大小写,MM和mm被认为是相同的格式代码,所以用mi替代mm

yyyy-MM-dd HH24:mi:ss:代表oracle中的24小时制,例:2020/1/7 13:21:55
yyyy-MM-dd HH:mi:ss: 代表oracle中的12小时制,例:2020/1/7 9:21:55

之所以 oracle和java不同,是因为我们知道oracle是不区分大小写的,所以java中根据大小写来代表24小时和12小时的表达式在oracle中就会出问题,oracle中将24小时的时和分做了特殊处理.如上所示,在hh后面加上了24,将mm改为了mi.
Java:

注意
Oracle数据库,今天根据时间日期查询展示数据,SQL语句是:
SELECT * FROM JCTJ_JXDB WHERE
DATAMONTH = TO_DATE(‘2021-11-29 15:12:54’,‘YYYY-MM-dd HH:mm:ss’),然后提示报错信息
SQL 错误 [1810] [22008]: ORA-01810: 格式代码出现两次
主要原因是由于Qracle中不区分大小写,MM和mm被认为是相同的格式代码,所以Oracle的SQL采用了mi代替分钟,如下修改为如下SQL即可:SELECT * FROM JCTJ_JXDB WHERE
DATAMONTH = TO_DATE(‘2021-11-29 15:12:54’,‘YYYY-MM-dd HH:mi:ss’),执行后,报如下错误提示:小时值必须介于1和12之间
这是由于我们使用的24小时制,如果我们的时间在0-12之间,是可以使用HH表示的,但现在我们查询的小时为15,大于12,所以在查询中需要使用HH24来表示小时

Java代码(基于SimpleDateFormat,计算任意符合日期格式的变量类型与当前时间差)

SimpleDateFormat
SimpleDateFormat格式化日期的方法和参数
SimpleDateFormat 报错:Unparseable date:String日期格式和format不匹配
String—SimpleDateFormat(format) —》Date
DateUtil工具类:

         String lastTime="";String format="yyyy-MM-dd HH:mm:ss.SSS";//指定字符串的日期格式Long Day=DateUtil.currentDifferenceD(lastTime,format);if(Day==null) throw new IllegalArgumentException("Object转化Date求时间差失败,String日期格式和format不匹配");Long hour=DateUtil.currentDifferenceH(lastTime,format);if(hour==null) throw new IllegalArgumentException("Object转化Date求时间差失败,String日期格式和format不匹配");Long minute=DateUtil.currentDifferenceM(lastTime,format);if(minute==null) throw new IllegalArgumentException("Object转化Date求时间差失败,String日期格式和format不匹配");Long s=DateUtil.currentDifferenceS(lastTime,format);if(s==null) throw new IllegalArgumentException("Object转化Date求时间差失败,String日期格式和format不匹配");Long sss=DateUtil.currentDifferenceSSS(lastTime,format);if(sss==null) throw new IllegalArgumentException("Object转化Date求时间差失败,String日期格式和format不匹配");

工具类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class DateUtil {private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);private DateUtil(){}/*** 计算参数与当前时间的天数差* lastTime:传入的符合format日期格式的对象* format:指定字符串的日期格式,然后根据日期格式解析String转为Date* return:若是传回null则Object转化Date失败*/public static Long currentDifferenceD(Object time,String format){String lastTime=time.toString();try {//当前日期Date dateNew = new Date(System.currentTimeMillis());//将数据库中String类型日期转化为Date类型SimpleDateFormat formatter= new SimpleDateFormat(format);//此方法仅可用于String类型转为Date类型,所以参数需要先转化为String类型Date date = formatter.parse(lastTime);Long nd=1000*60*60*24L;
//        获得各个时间的毫秒时间差异 Date.getTime()返回自从GMT 1970-01-01 00:00:00到此Date对象上时间的毫秒数。Long diff=dateNew.getTime()-date.getTime();diff=diff/nd;//计算差多少天return diff;} catch (ParseException e) {logger.error(e.getMessage());}return null;}/*** 计算参数与当前时间的小时差* lastTime:传入的符合format日期格式的对象* format:指定字符串的日期格式,然后根据日期格式解析String转为Date* return:若是传回null则Object转化Date失败*/public static Long currentDifferenceH(Object time,String format){String lastTime=time.toString();try {//当前日期Date dateNew = new Date(System.currentTimeMillis());//将数据库中String类型日期转化为Date类型SimpleDateFormat formatter= new SimpleDateFormat(format);Date date = formatter.parse(lastTime);Long nh=1000*60*60L;
//        获得各个时间的毫秒时间差异 Date.getTime()返回自从GMT 1970-01-01 00:00:00到此Date对象上时间的毫秒数。Long diff=dateNew.getTime()-date.getTime();diff=diff/nh;//计算差多少小时return diff;} catch (ParseException e) {logger.error(e.getMessage());}return null;}/*** 计算参数与当前时间的分钟差* lastTime:传入的符合format日期格式的对象* format:指定字符串的日期格式,然后根据日期格式解析String转为Date* return:若是传回null则Object转化Date失败*/public static Long currentDifferenceM(Object time,String format){String lastTime=time.toString();try {//当前日期Date dateNew = new Date(System.currentTimeMillis());//将数据库中String类型日期转化为Date类型SimpleDateFormat formatter= new SimpleDateFormat(format);Date date = formatter.parse(lastTime);Long nd=1000*60L;
//        获得各个时间的毫秒时间差异 Date.getTime()返回自从GMT 1970-01-01 00:00:00到此Date对象上时间的毫秒数。Long diff=dateNew.getTime()-date.getTime();diff=diff/nd;//计算差多少分钟return diff;} catch (ParseException e) {logger.error(e.getMessage());}return null;}/*** 计算参数与当前时间的秒差* lastTime:传入的符合format日期格式的对象* format:指定字符串的日期格式,然后根据日期格式解析String转为Date* return:若是传回null则Object转化Date失败*/public static Long currentDifferenceS(Object time,String format){String lastTime=time.toString();try {//当前日期Date dateNew = new Date(System.currentTimeMillis());//将数据库中String类型日期转化为Date类型SimpleDateFormat formatter= new SimpleDateFormat(format);Date date = formatter.parse(lastTime);Long nd=1000L;
//        获得各个时间的毫秒时间差异 Date.getTime()返回自从GMT 1970-01-01 00:00:00到此Date对象上时间的毫秒数。Long diff=dateNew.getTime()-date.getTime();diff=diff/nd;//计算差多少秒return diff;} catch (ParseException e) {logger.error(e.getMessage());}return null;}/*** 计算参数与当前时间的毫秒差* lastTime:传入的符合format日期格式的对象* format:指定字符串的日期格式,然后根据日期格式解析String转为Date* return:若是传回null则Object转化Date失败*/public static Long currentDifferenceSSS(Object time,String format){String lastTime=time.toString();try {//当前日期Date dateNew = new Date(System.currentTimeMillis());//将数据库中String类型日期转化为Date类型SimpleDateFormat formatter= new SimpleDateFormat(format);Date date = formatter.parse(lastTime);
//        获得各个时间的毫秒时间差异 Date.getTime()返回自从GMT 1970-01-01 00:00:00到此Date对象上时间的毫秒数。Long diff=dateNew.getTime()-date.getTime();return diff;} catch (ParseException e) {logger.error(e.getMessage());}return null;}}

Date日期转化为Long类型

注意:String可以作为任意类型转化为Date类型的中介。
Object.toString()---->String–SimpleDateFormat.parse–>Date
Date–SimpleDateFormat.format–>String---->Object.parseObject(String)
因为日期可能为YYYYMMDD八位或者毫秒数更多所以只能用Long来存储,防止越界。

between…and…:可用于字符串以及日期

    /*** 将Date类型转化为Long类型*/public static Long dateToLong(Date date,String format){SimpleDateFormat formatter= new SimpleDateFormat(format);String time=formatter.format(date);return Long.parseLong(time);//String类型转为Long类型}

获得当前YYYYMM减去三个月后的YYYYMM

        SimpleDateFormat formatter= new SimpleDateFormat("yyyyMMdd");Calendar cal = Calendar.getInstance();cal.add(Calendar.MONTH, -3);Date result = cal.getTime();String lastMonth=formatter.format(result);System.out.println(lastMonth);
        //用毫秒数初始化构建Date对象Date dateNew = new Date(System.currentTimeMillis());SimpleDateFormat formatN = new SimpleDateFormat("yyyyMM");//获取1970-01-01 00:00:00到此Date对象上时间的毫秒数(初始化构建该对象的毫秒数)==System.currentTimeMillis().Long date = dateNew.getTime();//减去三个月的毫秒数date = date - 93L * 24L * 60L * 60L * 1000L;//操作完Long后再次初始化构建Date对象dateNew = new Date(date);String delMonth = formatN.format(dateNew);

获取当前Date日期的不同YMD格式String

    /*** 获取当前日期YYYYMMDD格式*/public static String getDateYYYYMMDD(){//当前日期Date dateNew = new Date(System.currentTimeMillis());SimpleDateFormat formatN=new SimpleDateFormat("yyyyMMdd");return formatN.format(dateNew);}/*** 获取当前账期YYYYMM格式*/public static String getDateYYYYMM(){//当前日期Date dateNew = new Date(System.currentTimeMillis());SimpleDateFormat formatN=new SimpleDateFormat("yyyyMM");return formatN.format(dateNew);}

Calender实现日期变化操作

Calender得到上月末后几天日期

例如:
正常情况下自己判断月末后五天是什么日期则需要考虑月份是30天还是31天如果是二月还要考虑闰年29天和平年28天情况。
Calender实现了这个功能。

        public static String getStartTime(int prevDay){Calendar c = Calendar.getInstance();Date date = c.getTime();//获取当前日期SimpleDateFormat formatN=new SimpleDateFormat("yyyyMMdd");String day =formatN.format(date).substring(6);//获取当天日期的天数int preDay = Integer.parseInt(day) + prevDay - 1;//获取当前天数与上个月倒数第prevDay天的差值c.add(Calendar.DATE,-(preDay));//当前日期减去插值return formatN.format(c.getTime());}

得到传入月份的上月末后prevDay天日期
传入:20221011,1
返回:20220930

    public static String getLastStartTime(String lastTime,int prevDay) {try{SimpleDateFormat formatN = new SimpleDateFormat("yyyyMMdd");Date date =formatN.parse(lastTime);Calendar c = Calendar.getInstance();c.setTime(date);String day = formatN.format(date).substring(6);int preDay = Integer.parseInt(day) + prevDay - 1;c.add(Calendar.DATE, -(preDay));return formatN.format(c.getTime());}catch (ParseException e) {logger.error(e.getMessage());}return null;}

Calender获得月份天数

   /*** 传入时间 获得天数 如果要得到其他月份的天数 设置对象的月份以及年份即可* */public static int getMonthDay(String yyyymm) {Calendar a = Calendar.getInstance();//获取当前时间Integer year= Integer.valueOf(yyyymm.substring(0,4));Integer month=Integer.valueOf(yyyymm.substring(4));a.set(Calendar.YEAR, year);a.set(Calendar.MONTH, month - 1);// Calendar月份是以0开始的 所以要-1a.set(Calendar.DATE, 1);//把日期设置为当月第一天a.roll(Calendar.DATE, -1);//日期回滚一天,也就是最后一天int day = a.get(Calendar.DATE);return day;}

Calender获取上月月份(YYYYMM)

    /*** 获取上月月份*/public static String getLastMonth(){SimpleDateFormat format = new SimpleDateFormat("yyyyMM");Date date = new Date();Calendar calendar = Calendar.getInstance();// 设置为当前时间calendar.setTime(date);calendar.add(Calendar.MONTH,-1);// 设置为上一个月date = calendar.getTime();return format.format(date);}

StrUtil工具类(StringBuffer)

String类型传递
先说结论,String类型传递与基本数据类型的传递效果相似。
说明:
String类对象一旦创建,其内容不可更改:
String类的所有方法都不会改变String类对象内容,要改变String类对象的值就必须创建一个新的String对象。
也就是说,当进行参数传递时,如果方法内对String类对象的值进行了修改,那么实际上是创建了一个新的String类对象,然后让原来的变量指向它而已。但是这个“原来的变量”是一份拷贝副本,只是一开始创建的时候与主方法中的传递的值相同而已,现在改变之后,两者就毫无关系了。

字符串拼接方法

Java中方法的参数传递机制以及形参个数可变的方法

    /*以可变个数形参来定义方法,可传入任意个数String字符串参数String... strings*/public  static String strSplice(String... strings){StringBuffer stringBuffer=new StringBuffer();for(String s:strings){stringBuffer.append(s);}return stringBuffer.toString();}

File文件操作

JAVA - 按行读取文件

  /*** 文件按行解析*/public static Map<Integer, String> parseFile(String path, String fileName) {File file = new File(path + "/" + fileName);Map<Integer, String> lineData = new HashMap<>(16);try (BufferedReader reader = new BufferedReader(new FileReader(file));) {String tempString = null;int line = 0;while ((tempString = reader.readLine()) != null) {lineData.put(++line, tempString);}} catch (Exception e) {logger.error(e.getMessage());}return lineData;}

JAVA - 将数据生成为TXT文件(PrintWriter)

JAVA - 将数据生成为TXT文件(可追加append,可重写)

JSONArray用法
测试用例
注意:java中表示文件夹目录是类似如下格式(结尾是\\否则认定最后一层为文件名)
windows路径格式
String path=“D:\\Atemp\\…\\”;
linux路径格式
String path=“/home/xxx/data/…/”;

JSONArray jsonArray=new JSONArray();JSONObject obj = new JSONObject();JSONObject obj1 = new JSONObject();obj.put("orderId",456);obj.put("packageId", 789);obj.put("startTime", 789);obj1.put("orderId",456);obj1.put("packageId", 789);obj1.put("startTime", 789);jsonArray.add(obj);jsonArray.add(obj1);// 这是用于访问操作系统临时目录的属性名称// 或文件夹。String property = "java.io.tmpdir";// 获取临时目录并打印。String tempDir = System.getProperty(property);System.out.println("OS temporary directory is " + tempDir);createTxtFile(jsonArray,tempDir,"AAA");
  public static boolean createTxtFile(JSONArray jsonArray, String path, String filename) {// 标记文件生成是否成功boolean flag = true;try {// 含文件名的全路径String[] strings = {path, filename, ".txt"};String fullPath = StrUtils.strSplice(strings);File file = new File(fullPath);File folder = new File(path);if (!folder.exists() && !folder.isDirectory()) {// 如果不存在,创建文件夹folder.mkdirs();}if (!file.exists()) {file.createNewFile();}// 格式化浮点数据NumberFormat formatter = NumberFormat.getNumberInstance();// 设置最大小数位为10formatter.setMaximumFractionDigits(10);// 格式化日期数据SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");// 遍历输出每行PrintWriter pfp = new PrintWriter(new FileOutputStream(file, true));for (int i = 0; i < jsonArray.size(); i++) {JSONObject jsonObject = jsonArray.getJSONObject(i);if (jsonObject.isEmpty()) {break;}StringBuilder thisLine = new StringBuilder("");for (Iterator<String> iterator = jsonObject.keySet().iterator(); iterator.hasNext(); ) {// 当前字段String key = iterator.next();Object obj = jsonObject.get(key);// 格式化数据String field = "";if (null != obj) {if (obj.getClass() == String.class) {// 如果是字符串field = (String) obj;} else if (obj.getClass() == Double.class || obj.getClass() == Float.class) {// 格式化浮点数,使浮点数不以科学计数法输出field = formatter.format(obj);} else if (obj.getClass() == Integer.class || obj.getClass() == Long.class|| obj.getClass() == Short.class || obj.getClass() == Byte.class) { // 如果是整形field += obj;} else if (obj.getClass() == Date.class) {// 如果是日期类型field = sdf.format(obj);}} else {// null时给一个空格占位field = " ";}// 拼接所有字段为一行数据,用逗号分隔// 不是最后一个元素if (iterator.hasNext()) {thisLine.append(field).append(",");} else {// 是最后一个元素thisLine.append(field);}}pfp.print(thisLine.toString() + "\n");}pfp.close();} catch (Exception e) {flag = false;log.error("生成txt文件失败", e);}return flag;}

JAVA流操作结束后为什么要关闭流

需要自己close的东西,一般都是用了虚拟机之外的资源,例如端口,显存,文件等,虚拟机无法通过垃圾回收释放这些资源,只能你显式调用close方法来释放。

许多情况下,如果在一些比较频繁的操作中,不对流进行关闭,很容易出现输入输出流经超越了JVM的边界,所以有时可能无法回收资源。
所以流操作的时候凡是跨出虚拟机边界的资源都要求程序员自己关闭,不要指望垃圾回收。

你读写一个文件,忘记关闭了流,你在操作系统里对这个文件的写,删除等操作就会报错,告诉你这个文件被某个进程占用

JAVA-文件删除

此方法是遍历给定file目录下的全部文件夹以及文件查找对应fileName文件来删除。

public class Demo {public static void main(String[] args) {//创建File对象,给定磁盘目录File file = new File("D:\\work");//设定待删除文件的名称String fileName = "xxx.txt";//把file对象传递给方法getFiledeleteFile(file,fileName);}public static void deleteFile(File file, String fileName) {if (file.exists()) {//获取file类的所有文件和目录File[] files = file.listFiles();if (files != null) {for (File f : files) {//判断是否为目录,如果为目录则利用递归继续进行寻找文件if (f.isDirectory()) {deleteFile(f, fileName);}//不是目录,那就是文件,则判断文件后缀是否为.txt,如果是则删除if (f.getName().equals(fileName)) {System.out.println(f.getName());f.delete();//log.infor(fileName + "文件删除完毕!")System.out.println(fileName + "文件删除完毕!");}}}}}

java file 跨盘符_File类——遍历盘符根目录查找文件报错 java.lang.NullPointerException.

注意:一定要判断file.exists并且files!=null才可以继续执行。
因为遍历到System Volume Information目录时,用户没有访问权限,所以调用file.listFile方法会返回null给files数组而不是file目录下的全部文件,所以循环体中数组元素调用方法的时候会产生空指针异常。

System Volume Information”是windows系统文件夹

是隐藏文件

中文名称可以翻译为“系统卷标信息”

这个文件夹里就存储着系统还原的备份信息

System Volume Information 文件夹是一个隐藏的系统文件夹

"系统还原"工具使用该文件夹来存储它的信息和还原点

例如:

SpringBoot

SpringBoot注解

Spring全家桶回顾

启动类位置注意事项(一定要注意文件结构)

SpringBoot启动类配置@Scan扫描包注解后,对应basePackages = "XXX.xxx"包下的类或接口等就不需要再添加对应@注解了。
 

AppApplication 一定要在包的最外层,否则Spring无法对所有的类进行托管,会造成@Autowired 无法注入。
这是因为SpringBoot项目的注解Bean装配默认规则是根据AppApplication 类所在的包位置从上往下扫描!即只会扫描AppApplication 所在的包及其子包,其他包路径不会被扫描!!!

若想扫描其他包中配置类则需要配置@ComponentScan。

@MapperScan

作用:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类。
配置扫描的是java接口不是xml文件,而maven默认不扫描xml文件,需要单独配置maven扫描xml文件。
@MapperScan注解

———————————————— 版权声明:本文为CSDN博主「哈6哈6」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/baidu_27636661/article/details/90487066

SpringBoot+MybatisPlus的MVC模板

Mybatis积累
注解版Mapper省去了绑定xml和Mapper类的步骤,直接将SQL以及数据库和Mapper方法绑定在一起。

SpringBoot定时任务

定时任务就是定时触发service方法。
SpringBoot定时任务
启动类添加注解:@EnableScheduling,定时类添加注解:@Component,定时方法添加注解@Scheduled(cron=“cron表达式”或fixed注解)
@EnableScheduling //可以在启动类上注解也可以在执行调度任务类

@Scheduled(fixedRate = 5000) :上一次开始执行时间点之后5秒再执行
@Scheduled(fixedDelay= 5000) :上一次执行完毕时间点之后5秒再执行
@Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
@Scheduled(cron="0*/1 * * * ? ") :通过cron表达式定义规则,表示每隔1分钟执行一次

slf4j的简单用法以及与log4j的区别

log的最大好处是可以在docker容器的终端环境中查看对应记录。
slf4j的简单用法以及与log4j的区别

package cn.xm.exam.test;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Slf4jTest {private static Logger logger = LoggerFactory.getLogger(Slf4jTest.class);// slf4j日志记录器public static void main(String[] args) {// 普通的日志记录logger.debug("普通的日志记录");// {}占位符记录日志for (int i = 0; i < 3; i++) {logger.debug("这是第{}条记录", i);}// 用\转义{}logger.debug("Set \\{} differs from {}", "3"); // output:Set {} differs// from 3// 两个参数logger.debug("两个占位符,可以传两个参数{}----{}", 1, 2);// 多个参数(可变参数)logger.debug("debug:多个占位符,{},{},{},{}", 1, 2, 3, 4);// 多个参数(可变参数)logger.info("info:多个占位符,{},{},{},{}", 1, 2, 3, 4);// 多个参数(可变参数)logger.error("error:多个占位符,{},{},{},{}", 1, 2, 3, 4);}}

@Slf4j是用作日志输出的,一般会在项目每个类的开头加入该注解,如果不写下面这段代码,并且想用log

private final Logger logger = LoggerFactory.getLogger(当前类名.class);

就可以用@Slf4来代替;这样就省去这段很长的代码。
默认log变量实现对应功能。


@Controller
@RequestMapping("/abc")
@Slf4j
public class QueryBillController {@Autowiredprivate TraceService traceService;@Autowiredprivate SignatureAndVerification signatureAndVerification;/*** 账单查询接口*/@RequestMapping(.........)@ResponseBodypublic String getBills(@RequestBody String queryRequest) {log.info("进入账单查询接口");

添加了该注释之后,就可以在代码中直接使用log.info( ) 等打印日志了

Mybatis-Plus

写好SQL后先去数据库跑跑看看是否正确。

Mybatis-Plus的自定义SQL操作(注解版)

下图对应的Mapper层和service层以及serviceImpl层的类声明以及注解(@Mapper,@Service)都是MP规范格式模板。
实现了MP制定好的简单单表CRUD方法声明(Service)和方法实现(ServiceImpl基于VoMapper),只需要传参VoMapper和Vo即可.(若多个数据库则需要@DS指定进行自定义SQL操作,不可用封装方法)
interface接口都是声明crud方法,class才是基于实例化base/VoMapper等实现crud方法
继承复用了MP制定的规范格式模板,可以直接Mapper调用MP封装的CRUD方法实现功能

model层(实体类命名与数据字段名要协调)
原理:Vo实体类变量封装映射的是select的结果集,可以通过as给结果集起别名来匹配Vo的变量名。
mybatis的sql中字段两种映射(映射到实体)方式

@TableField(select = false)    //查询时,则不返回该字段的值
@TableField(value = "字段名")    //通过tableField进行字段名和变量名不一致的映射
@TableField(exist = false)  //声明该字段在数据库表中不存在,不参与数据库表的映射
@Data
public class Vo{private Long 对应数据表 bigInt
private String 对应数据表 varchar
}

mapper层固定crud教程

自定义Vomapper继承baseMapper的作用主要是基于baseMapper简单单表crud的基础上,添加自定义crud方法。
mybatis中的#和$的区别

大多数情况下还是经常使用#,一般能用#的就别用$;但有些情况下必须使用$,传入表名或字段名的时候,例:MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
#传入的参数在SQL中显示为字符串,$传入的参数在SQL中直接显示为传入的值.

#不需要加’‘,本身自带’',$需要按照情况分析。

效果上: #{}=‘${}’=‘参数’

SQL中字符串可以直接比较,并且其它类型也可以直接转为字符串比较。

where id = 66和where id = '66'等效

@Param
首先明确这个注解是为SQL语句中参数赋值而服务的。

  @Param的作用就是给参数命名,比如在mapper里面某方法A(int id),当添加注解后A(@Param("userId") int id),也就是说外部想要取出传入的id值,只需要取它的参数名userId就可以了。将参数值传如SQL语句中,通过#{userId}进行取值给SQL的参数赋值。
@Mapper
@DS("该类全部SQL方法调用的数据库")
//若整个项目仅有一个数据库则忽略该注解,若该注解加在方法上则是表示仅限该方法调用的数据库
public interface  VoMapper extends BaseMapper<Vo> {@Select("此处填写select的SQL语句并且表示填充的#{参数名A}")public List<Vo> queryVo(@Param("参数名A") String 参数B);
}

形参为对象

@Mapper
@DS("该类全部SQL方法调用的数据库")
//若整个项目仅有一个数据库则忽略该注解,若该注解加在方法上则是表示仅限该方法调用的数据库
public interface  VoMapper extends BaseMapper<Vo> {@Select("此处填写select的SQL语句并且表示填充的#{vo对象A.变量名}")public List<Vo> queryVo(@Param("vo对象A") Vo vo);
}

insert
SQL INSERT INTO 语法
INSERT INTO 语句可以有两种编写形式。

第一种全值插入形式无需指定要插入数据的列名,只需提供被插入的值即可:

INSERT INTO table_name
VALUES (value1,value2,value3,...);

第二种形式需要指定列名及被插入的值:

INSERT INTO table_name (column1,column2,column3,...)
VALUES (value1,value2,value3,...);

update
SQL UPDATE 语法

UPDATE table_name
SET column1=value1,column2=value2,...
WHERE some_column=some_value;

批量操作

固定格式
<foreach>标签中的为循环遍历List数组拼接的SQL语句。

@crud({"<script>" +"<foreach collection=\"list数组名\" item=\"数组元素\" separator=\";\">" +"SQL语句和参数""</foreach>" +"</script>"})void method(@Param("list数组名")List数组);

list批量插入
@Insert批量插入
Mybatis积累(5):注解实现批量插入

@Repository
public interface UserMapper {public String tableName = "user";public String column = "username, password";@Insert("<script> " +"insert into " + tableName +"(" + column + ") " +"values " +"<foreach collection=\"items\" index=\"index\" item=\"item\" separator=\",\"> "+"(#{item.username},#{item.password})"+"</foreach> " +"</script>")int batchSave(@Param("items") List<User> items);

update批量更新

@Update({"<script>" +"<foreach collection=\"userInfoList\" item=\"item\" separator=\";\">" +" UPDATE" +" train_learn_task_user_info" +" SET completion_status = #{item.completionStatus, jdbcType=VARCHAR}" +" WHERE" +" id = #{item.id, jdbcType=BIGINT}" +"</foreach>" +"</script>"})void batchUpdate (@Param("userInfoList") List<LearnTaskUserInfo> userInfoList);

if-else
注意:case when then 只能用在select
固定开始:CASE
when (字段旧值判断) then 字段新值
else 字段新值
固定结束:END
as 别名

(case
when (prov_code is NULL or prov_code='') then '00'
else prov_code
end)
as provCode

service层
IService定义了简单单表的crud接口方法。

public interface VoService  extends IService<Vo> {public List<Vo> queryVo(String 参数);
}

(重点)serviceImpl层
注意:MP封装的ServiceImpl通过baseMapper实现了service层IService中的基础crud方法框架,只需要自定义传参VoMapper extends BaseMapper<Vo>就可以实现功能了,可以ctr+左击进入查看一下。
Iservice定义的crud接口方法已经在ServiceImpl中用basemapper实现了框架,只缺VoMapper和Vo参数。

VoServiceImpl继承ServiceImpl实现的Service接口方法后就不需要再次实现对应接口方法。
只需要实现自定义的crud方法并且可以借助继承的baseMapper实现对应功能。

@Service
public class VoServiceImpl extends ServiceImpl<VoMapper, Vo> implements VoService {@ResourceVoMapper voMapper;@Overridepublic List<Vo> queryVo(String 参数) {//用自定义的VoMapper方法实现Service功能return voMapper.queryVo(参数);}
}

controller层
@RequestParam注解详细使用

  • @RequestMapping是一个无请求方法的注解。@GetMapping和@PostMapping是组合注解,分别是@RequestMapping(method = RequestMethod.GET)和@RequestMapping(method = RequestMethod.POST)的缩写。
  • 用POSTMapping和GetMapping代替RequestMapping,简化controller方法头注解。
  • @RequestMapping(value = “/Spath”, produces = “application/json;charset=UTF-8”, method = RequestMethod.GET)== @GetMapping(value = “/Spath”, produces = “application/json;charset=UTF-8”)
默认:@RequestParam==@RequestParam(value="参数名",required=true) String 参数名
特殊:@RequestParam(value="URL参数名",required=false) String 参数名

required=false:当URL中没有对应参数的时候也不报错而是给参数赋值为NULL。
注意:参数需为包装类
因为int,long等不能赋值为NULL。
若是required=true则基本数据类型就可以使用了。

@RequestParam和@RequestBody引入的get和post理解
POST、GET、@RequestBody和@RequestParam区别
@RequestParam可用于提取Get(URL)中请求参数。
@RequestBody只可用于提取Post的Body中的JSON请求参数封装到Vo实体类不可以用基本数据类型及其包装类作为参数。

若是请求参数名和映射参数名一致则不需要特殊使用注解进行捆绑映射.

@RestController
@Slf4j
@RequestMapping("/Fpath")
public class VoController {@ResourceVoService voService;//此处注入的VoServiceImpl@RequestMapping(value = "/Spath", produces = "application/json;charset=UTF-8", method = RequestMethod.GET)public List<Vo> queryVo(@RequestParam(value="URL参数名",required=false) String 参数名){return voService.queryVo(参数);}
}
  • @RequestMapping(value = “/Spath”, produces = “application/json;charset=UTF-8”, method = RequestMethod.POST)== @PostMapping(value = “/Spath”, produces = “application/json;charset=UTF-8”)

HttpServletRequest详解
getParameter(String name) 根据name获取请求参数(常用)类Get方法
getParameterValues(String name) 根据name获取请求参数列表(常用)

@RestController
@Slf4j
@RequestMapping("/Fpath")
public class VoController {@PostMapping("/Spath")
public ReturnMsg trigger(HttpServletRequest request, @RequestBody Vo vo) {Object x = vo.getDateTimeFmt();Object y = request.getParameter("S");//此处就是将URL(请求行)的S参数提取出来类似Get方法}
}

注意:SpringMVC @RequestParam
SpringMVC @RequestParam 推荐使用包装类型

required=false:当URL中没有对应参数的时候也不报错而是给参数赋值为NULL。
注意:参数需为包装类
因为int,long等不能赋值为NULL。
若是required=true则基本数据类型就可以使用了。

此处统一规定,参数全部使用基本数据类型的(首字母大写)包装类,保证不会出错。
String不属于基本数据类型为包装类。

Mybatis_Plus的debug步骤

若是dao层SQL报错则从console复制传参SQL,到对应数据库跑跑试试看看具体问题
查看mp提供的拼接后的SQL,若排除SQL语法错误而是SQL不完整的原因报错则必因为service层传参值为空导致的SQL拼接报错。
例如:insert拼接不全SQL报错则是因为传参为空,导致values后面无值。

实战总结

乐观锁处理多线程“抢占”现象

两个SQL实现乐观锁

点睛之笔:单个SQL语句事务实现where判断和update占位

mp乐观锁实现方式:

  • First SQL:取出记录时,获取当前version(查)
    select version from table
  • Second SQL:更新时,带上这个version
  • 执行更新时
    update
    set version = newVersion (后占位)
    where version = oldVersion(先判断空位)
  • 如果version不对,就更新失败
    (先判后占)

乐观锁用于处理多线程’抢’现象
不只是乐观删除,乐观占用也行
乐观锁处理后则只有一个用户可以抢占成功,其余用户where判断空位失败

Java杂七杂八(做完要验证)相关推荐

  1. Java能做什么?学完Java可以从事什么工作呢?

    如果你是一个Java初学者,你可能对Java应用在什么地方感到困惑.除了"马里奥""贪吃蛇"等经典游戏,其他领域好像也找不到Java的踪迹,那么Java究竟能做 ...

  2. 几天后自动领取java怎么做的_学了14天,终于把Java项目一做完啦

    原标题:学了14天,终于把Java项目一做完啦 今天是刘小爱自学Java的第113天. 感谢你的观看,谢谢你. 话不多说,开始今天的学习: 今天过后项目一也就算是结束了. 明天开始学SSM框架,再用S ...

  3. 学完Java可以做什么兼职?去哪里找兼职?

    最近有些同学表示我感觉自己Java可学的差不多了,想要找一些兼职一方面锻炼自己,一方面还能赚点外快,那么学Java的到底应该怎么做兼职呢?本篇来解答一下这个问题. 学完Java可以做什么兼职? 能做的 ...

  4. java文件下载做apk安装包下载,当下载类型为.apk时,用手机谷歌浏览器下载完后点击打开不能直接启动安装,而是打开压缩文件管理。

    java文件下载做apk安装包下载,当下载类型为.apk时,用手机谷歌浏览器下载完后点击打开不能直接启动安装,而是打开压缩文件管理. uc浏览器可以正常,自带的谷歌不正常,解决方法为,在下载设置res ...

  5. Java + Selenium 完成简单滑块验证学习之路(破解无缺口滑块验证码)(三)

    破解无缺口滑块验证码 在学习完selenium 简单操作之后,继续我的破解之路.先看一下原网页页面.(灵魂打码重点看滑块) 破解这种无缺口滑块首先要找到滑块位置,根据selenium选择器去选择要拖动 ...

  6. 小猿圈讲解Java可以做什么?

    前几天有个小伙伴问我学完Java可以做什么?对于大部分人只知道Java是编程语言的一种,但是具体的能做什么确不是很了解,针对这样的现象,小猿圈给大家讲解一下Java可以做什么? 1. 大数据 大数据领 ...

  7. web前端面试题:20道做完信心嫉妒膨胀的测试题

    经常有前端的同学说去面试的时候被企业的面试题搞得很心伤,感觉自己什么都不会了!今天小千就带给大家20道能让你疯狂增加信心的面试题,废话不多说赶紧来做题吧~ 1.Vue框架的作者是谁? A.秦始皇 B. ...

  8. Java应用程序中的验证

    我经常看到的项目几乎没有任何有意识的数据验证策略. 他们的团队在截止日期,明确要求的巨大压力下工作,只是没有足够的时间以适当且一致的方式进行验证. 因此,数据验证代码随处可见:JavaScript片段 ...

  9. Java好学吗?Java能做什么?如何快速入门Java?

    Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,Java具有简单性.面向对象.分布式.健壮性.安全性.平台独立与可移植性.多线程.动态性等 ...

最新文章

  1. SpringMVC——通俗易懂讲讲Ajax~
  2. python计算wav的语谱图_Python实现电脑录音(含音频基础知识讲解)
  3. 使用jQuery.Ajax向ASP.NET MVC控制器Post数据
  4. OpenGL实现3D魔方游戏源代码
  5. 用户思维模型,围绕用户核心四大模块,拉新、养熟、成交、裂变循环的效果...
  6. c语言循环字符,字符串 非暴力for循环法(内附C语言代码)
  7. P1616 疯狂的采药(洛谷,动态规划递推,完全背包)
  8. JavaWeb调用python脚本(可传参)
  9. 贪心算法——部分背包(洛谷 P2240)
  10. 关于bottle WEB框架中签名cookie的一点理解
  11. Kubernetes 1.5安装
  12. 深入理解计算机系统(2.7)------二进制小数和IEEE浮点标准
  13. 10月全球浏览器份额态势:Chrome领先Firefox7.34%
  14. 多个python则可以通过指定python的位置来升级或安装对应的库
  15. Zlib文件压缩和解压
  16. python检测刀具_科研一角|Python语言在人工智能加工中心机器人方面的应用
  17. cf(穿越火线)进游戏乱码问题解决方案
  18. 计算机无法识别移动硬盘怎么办,移动硬盘不能识别,教您移动硬盘不能识别怎么办...
  19. list_for_each_entry解析
  20. Python多线程多进程应用场景

热门文章

  1. 北邮通信原理公开课 杨鸿文老师 课程学习笔记【第二课 复信号】
  2. 21.1 三目运算符
  3. 看《钱钟书手稿集·中文笔记》第2本
  4. 量化交易——传统技术分析随机震荡指标STO的原理及实现
  5. java方法名是什么_什么是java的方法
  6. TTL接口 液晶屏 与 LVDS接口 液晶屏的 区别
  7. 盛大、腾讯:文学江湖的格局与博弈
  8. 微信公众平台授权登录
  9. UE4开发HTML5遇到的问题
  10. 计算机科学与技术 色盲限制,2021男生色盲学什么专业比较好 受限专业有哪些