java开发小结
注解
@Serverice标记service类、business类
@Repository标记仓储类
@Autowired自动注入
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepository;
}
@Repository
public class StudentRepository {
}
String
好多String的Util。
import java.text.MessageFormat;
import org.apache.commons.lang3.StringUtils;
// 空字符串
var str = StringUtils.EMPTY;
var a = StringUtils.isEmpty(str);
var b = StringUtils.isNotEmpty(str);
var strArray = str.split(",");
var strArray2 = StringUtils.split("a,b",',');
// join
var ids = new List<Integer>();
ids.add(1);
ids.add(2);
StringUtils.join(ids,",")
// 用MessageFormat.format 代替 String.format
var str11 = String.format("id:{0} name:{1}", 111 ,1001);//没生效
var str12 = String.format("id:%s name:%s", 111 ,1001);//生效,没有千分号
var str22 = MessageFormat.format("id:{0} name:{1}", 111 ,1001);//注意:10001生成的字符串会有千分号
var str23 = MessageFormat.format("id:{0} name:{1}", 111 ,String.valueOf(1001));//没有千分号
Equals
基本数值类型与包装类的等值比较。
包装类对象为null时,==直接比较会抛异常。
Integer对象为null时,执行j instance of Integer
结果为false
。
package demo;
import java.util.Objects;
import org.junit.jupiter.api.Test;
import cn.hutool.core.util.ObjectUtil;
import static org.junit.jupiter.api.Assertions.*;
class IntegerEqualsTest {
@Test
public void intEqualsToIntegerNull_Error() {
assertThrows(NullPointerException.class, () -> {
int i = 0;
Integer j = null;
var result = i == j;
fail("no null pointer expected");
});
}
@Test
public void intObjectUtilEqualsToIntegerNull_Success() {
int i = 0;
Integer j = null;
var result = ObjectUtil.equals(i, j);
assertFalse(result);
}
@Test
public void intObjectsEqualsToIntegerNull_Success() {
int i = 0;
Integer j = null;
var result = Objects.equals(i, j);
assertFalse(result);
}
@Test
public void integerValueOfIntEqualsToIntegerNull_Success() {
int i = 0;
Integer j = null;
var result = Integer.valueOf(i).equals(j);
assertFalse(result);
}
@Test
public void integerNullInstanceofIntegerAsFalse(){
Integer j = null;
var result = j instanceof Integer;
assertFalse(result);
}
}
Json
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
var student = new Student();
var strStudent = JSON.toJSONString(student);
student = JSON.parseObject(strStudent, Student.class)
// 解析为列表
List<Student> students = new ArrayList<>();
students.add(student);
var strStudents = JSON.toJSONString(student);
students = JSON.parseArray(strStudents, Student.class);
// 复杂类型,如HashMap且map的值为复杂结构,见下
HashMap<String, Student> dataMap = JSON.parseObject(request.getData(), new TypeReference<HashMap<String, Student>>(){});
HashMap<String, Student> dataMap = JSON.parseObject(request.getData(), new TypeReference<>(){});
// 反例:在使用dataMap
HashMap<String, Student> dataMap = JSON.parseObject(request.getData(), HashMap.class);
for (var dataItem : dataMap.entrySet()) {
// 调用getValue会出现转换异常
var valueItem = dataItem.getValue();
}
DateTime
import java.time.LocalDateTime;
// 本地时间
var now = LocalDateTime.now();
var nowStr = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
var date = now.toLocalDate();
var time = now.toLocalTime();
// 用时ms
long startTime = System.currentTimeMillis();
var elapsedMs = System.currentTimeMillis() - startTime;
Array
import org.apache.commons.lang3.ArrayUtils;
String[] arr = new String[]{ "a","b","c" };
ArrayUtils.contains(arr,"a");
// List:交集Intersect
var ids1 = new ArrayList<Integer>(); ids1.add(1); ids1.add(2);
var ids2 = new ArrayList<Integer>(); ids2.add(1); ids2.add(3);
var ids3 = new ArrayList<Integer>(); ids3.add(2); ids3.add(4);
// ids1作为交集结果有改变,ids2不变
var flag = ids1.retainAll(ids2);
assertTrue(flag);
assertTrue(ids1.size()==1 && ids1.contains(1));
assertTrue(ids2.size()==2 && ids2.contains(1) && ids2.contains(3));
// ids3交ids2,ids3作为交集结果是空集合,ids2不变
var flag2 = ids3.retainAll(ids2);
assertTrue(flag);
assertTrue(ids3.isEmpty());
assertTrue(ids2.size()==2 && ids2.contains(1) && ids2.contains(3));
// Array to List
List<String> list = Arrays.asList(arr);
var arr2 = list.toArray();
var arr3 = list.toArray(new String[0]);
var arr4 = list.toArray(new String[list.size()]);
Collection
列表:List/ArrayList/LinkedList (最终会继承Collection)
字典:Map/HashMap/LinkedHashMap/ConcurrentHashMap(Map的values和keySet是Collection或最终继承Collection)
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
// .map(类似C#的select)
// .filter(类似C#的where)
// toList()、findFirst().orElse
List<String> names=new ArrayList<>();
names.add("tom");
List<Student> students = new ArrayList<>();
var ids = students.stream().map(x -> x.geId()).collect(Collectors.toList());
// orElse(null)有什么用,找不到时有和没有orElse会不会抛出异常?findFirst()返回Optional<T>,加orElse会返回T。
var firstOne = students.stream().filter(x -> x.getId() == 1).findFirst().orElse(null);
Map<String, String> map = new HashMap<>();
map.put("1","tom");
for (Map.Entry<String, String> entry : map.entrySet()) {
var val = entry.getKey() + entry.getValue();
}
// 按条件移除多个元素
names.removeIf(t -> t.contains("foo"));
// 类似C#的SelectMany
var students = new ArrayList<Student>();
var student1 = new Student();
var student1ClassInfos = new ArrayList<ClassInfo>();
var classInfo11 = new ClassInfo();classInfo11.setId(1);
var classInfo12 = new ClassInfo();classInfo12.setId(2);
student1.setClassInfos(student1ClassInfos);
var student2 = new Student();
var student2ClassInfos = new ArrayList<ClassInfo>();
var classInfo21 = new ClassInfo();classInfo21.setId(1);
var classInfo22 = new ClassInfo();classInfo22.setId(3);
student2.setClassInfos(student2ClassInfos);
students.add(student1);
students.add(student2);
var classIds = students
.stream()
.flatMap(t -> t.getClassInfos().stream().map(s -> s.geClassId()))
.distinct()
.collect(Collectors.toList());
// 交集
// 使用CollectionUtils.intersection
import org.apache.commons.collections4.CollectionUtils;
var list1 = new ArrayList<>(List.of(1,2,3));
var list2 = new ArrayList<>(List.of(1,2,4));
var resultCollection = CollectionUtils.intersection(list1,list2);
// 使用ArrayList.retainAll,据说会改变原集合,并且全真时返回false。比如以下会改掉list1
var success = list1.retainAll(list2);
Mapping
default自定义转换
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface StudentMapping {
StudentMapping INSTANCE = Mappers.getMapper(StudentMapping.class);
// 数据表字段与Dto字段名不一样的mapping处理
@Mapping(target = "name", source = "cnName")
StudentDto toDto(Student student);
// toDtoList的实现调用了上面的toDto
List<StudentDto> toDtoList(List<Student> students);
List<StudentExtDto> toDtoListExt(List<Student> students);
default StudentDto toDtoExt(Student student){
return null;
}
}
Lombok
使用lombok让实体类自带getter、setter。
在IDEA中,File >> Settings >> Plugins >> 搜索Lombok >> 安装。
增加注解@Data
对于boolean
(小写),lombok会生成isXXX而不是getXXX的getter,见下isInSchool()
,而对于大写Boolean
的处理与其他类型是一样的getXXX。
import lombok.Data;
@Data
public class Student {
private String name;
private boolean inSchool;
private Boolean inSchool2;
}
var student = new Student();
student.getName();
student.isInSchool();
student.setInSchool(true);
student.getInSchool2();
Lombok编译出错提示找不到符号
所遇到的情况是lombok 和mapstruct冲突引起的。使用方法是在pom文件maven-compiler-plugin的annotationProcessorPaths中,需要把lombok配置要放在mapstruct-processor之前
<properties>
<lombok.version>1.18.24</lombok.version>
</properties>
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
<annotationProcessorPaths>
<!-- lombok的配置要在mapstruct-processor之前 -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<propertiesEncoding>UTF-8</propertiesEncoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
Mongo
import org.bson.Document;
import org.bson.BsonDocument;
import com.alibaba.fastjson.JSON;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mngodb.core.query.Criteria;
import org.bson.Document;
import org.bson.BsonDocument;
import com.alibaba.fastjson.JSON;
var query = new Query();
var name = "tom";
var classNames = new ArrayList<>();
List<Integer> types = new ArrayList<>();
Criteria criteria = new Criteria();
criteria.and("_id").ne(id);
criteria.and("Name").is("foo");
var subCriteria = new Criteria().and("className").in(classNames);
criteria.and("Classes").elemMatch(subCriteria);
criteria.and("Types").in(types);
var query2 = new Query(criteria);
// 模糊查询
query.addCriteria(Criteria.where("Name").regex("^.*" + name + ".*$"));
// query生成的条件为{ "Name" : { "$regularExpression" : { "pattern" : "^.*tom.*$", "options" : ""}}}
# or
var orCriteria = new Criteria()
.orOperator(Criteria.where("_id").is(1L), Criteria.where("Name").is("Foo"));
var criteria = new Criteria()
.and("sex").is("boy")
.andOperator(orCriteria);
# sort两个字段,skip, limit
var query = new Query(criteria)
.with(Sort.by(Sort.Direction.DESC,"Name").and(Sort.by(Sort.Direction.DESC,"UpdateTime")))
.skip(skip)
.limit(limit);
// 将对象转为Document、BsonDocument,需要转Bson可查看org.springframework.data.mongodb.util.BsonUtils.asBson();
var student = new Student();
var json = JSON.toJSONString(student);
var document = Document.parse(json);
var bsonDocument = Document.parse(json).toBsonDocument();
var bsonDocument2 = BsonDocument.parse();
@Document(collection = "OperationLog")
@Data
public class OperationLog {
@Id
private String id;
@Field("ContentBefore")
private Object contentBefore;
}
var logEntity = new OperationLog();
logEntity.setContentBefore(student);// 写入db中嵌套字段id为.ContentBefore._id
// logEntity.setContentBefore(document);// 写入db中嵌套字段id为.ContentBefore.id
// logEntity.setContentBefore(bsonDocument);// 同上
// repo.insert(logEntity);
HttpRequest
RetrofitClient
import com.github.lianjiatech.retrofit.spring.boot.annotation.Intercept;
import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient;
@RetrofitClient(baseUrl = "${demo.service.url}")
@Intercept(handler = TraceInterceptor.class)
public interface StudentServiceClient {
@GET("/student/queryByName")
public Result<StudentDto> queryByName(@Query("name") String name);
@POST("/student/create")
public Result create(@Body CreateStudentRequest request);
}
WebApi
/**
* @GetMapping("getById")
* @PostMapping("getById")
* @RequestMapping同时支持Get和Post
*/
@RequestMapping(value = "getById", method = {RequestMethod.GET,RequestMethod.POST})
public String getById(){
return "foo";
}
错误处理:There is already 'xxxController' bean method
原因是controller中的@RequestMapping路径重复。
Log
log4j
package com.example.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JsonUtil {
private static final Logger log = LoggerFactory.getLogger(JsonUtil.class);
public void test(){
try{
log.info("test info");
}
catch(Exception e){
log.warn("error : {}", e.getMessage());
}
}
}
泛型Generic
import com.alibaba.fastjson.JSON;
public <T> List<T> doSome(){
return null;
}
public <T> List<T> doSome(String str, Class<T> clazz){
return JSON.parseArray(str, clazz);
}
Reflection
public class Student extends BaseEntity {
private long id;
private String name;
}
var student = new Student();
// 此方法不包含父类字段
var fields = student.getClass().getDeclaredFields();
// private字段需要设置accessble才可访问取值
field[0].setAccessible(true);
field[1].setAccessible(true);
var id = fields[0].getLong(student);
var name = fields[1].get(student).toString();
// 获取包含父类在内的字段
cn.hutool.core.util.ReflectUtil.getFields(student.getClass());
File
import org.springframework.util;
public static String readFileAsString(String filename) throws IOException {
var resource = new ClassPathResource(filename);
var bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
// copyToString(@Nullable Reader in)应该也可以,还没试过
return new String(bytes);
}
配置
student.properties
文件:
student.id=1
student.name=foo
配置类,@PropertySource可以指定配置文件,也可以不指定
@Component
@ConfigurationProperties(prefix = "student")
@PropertySource(value = "file:/mnt/demo/config/student.properties", ignoreResourceNotFound = true)
public class Student {
private Long id;
private String name;
}
应用
导入excel
EasyExcel
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
@ApiOperation("导入student")
@PostMapping("uploadStudents")
@FileType({"xlsx", "xls"})
public Object uploadStudents(MultipartFile file, @RequestHeader("teacherId") Long teacherId) throws IOException {
InputStream inputStream = file.getInputStream();
byte[] bytes = inputStream.readAllBytes();
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
var listener = new AnalysisEventListener<StudentUploadData>() {
private ArrayList<StudentUploadData> list = new ArrayList<>();
// 按批处理,每批行数
private int maxRow = 1000;
@Override
public void invoke(StudentUploadData data, AnalysisContext analysisContext) {
list.add(data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
int count = (int) Math.ceil((double) list.size() / maxRow);
for (int i = 0; i < count; i++) {
int fromIndex = i * maxRow;
int toIndex = fromIndex + maxRow;
if (toIndex > list.size()) {
toIndex = list.size();
}
List<T> subList = list.subList(fromIndex, toIndex);
// TODO:处理一批数据,比如保存
}
list.clear();
}
};
EasyExcel.read(inputStream, StudentUploadData.class, listener).sheet(0).headRowNumber(1).doRead();
inputStream.close();
return null;
}
IDE工具
IDEA运行调试
- 编译:在右侧Maven窗口的root>Lifecycle下,选中clear+validate+compile后点击上方Run Maven Build绿色三角按钮,等待编译完毕。
- 运行或调试:首次运行可以先找到目标host所在的ServiceInitializer,点击代码左侧的绿色三角按钮,在下列菜单中选择Run或Debug。
- 命名运行调试配置:工具栏运行按钮左边的下拉菜单列出运行过的host,默认名字为ServiceInitializer,在下拉菜单选中Edit Configuration对各host命名以便区分多host。
IDEA正则式替换字符串
- 比如想将dotnet字段注释改为java注释
// name
private String name;
/**
* name
*/
private String name;
操作:在IDEA替换对话框(ctrl+H)中选中正则式方式(图标为.*
),填写以下查找值和替换值
查找值:
// (.*)
替换值:
/**
* $1
*/
- 方法首字母大写转为小写
// 条件值:注意前面有一空格,本示例是查带左小括号的,并且选中`Cc`和`.*`(即大小写和正则)
([A-Z])(\w+\()
// 替换值:注意前面有一空格,`\l``\L`转为小写,`\u``\U`转为大写。
\l$1$2
示例
// 转换前
public String GetName() {}
// 转换后
public String getName() {}
- 给字段增加@Field注解,将名首字母大小后的字段名填写到注解
查找值:
( private .+ )(.+);
替换值:
@Field("\u$2")
$1$2;
示例
// 替换前
private String name;
// 替换后
@Field("Name")
private String name;
Maven包处理
- 清除IDEA缓存
在打开的项目中,File菜单>Invalidate Caches/Restart...>点击Invalidate Caches And Restart。将会清除Maven缓存并重新打开项目,重新拉取Maven包。
制作项目模板
https://maven.apache.org/archetype/maven-archetype-plugin/
依赖jar打包
我有一个非bootstrap项目,打包时没有包含依赖jar包,在pom文件的build>plugins中添加下面的plugin后,在idea的maven工具中选择以下项运行打包Plugins>assembly>assembly:assembly,可以得到jar-with-dependencies的jar包,里面包含了依赖包的class文件。
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
网友评论