java开发

2023-06-28  本文已影响0人  ljt001

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

array和list互转参考:

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运行调试

IDEA正则式替换字符串

// name
private String name;

/**
 * name
 */
private String name;

操作:在IDEA替换对话框(ctrl+H)中选中正则式方式(图标为.*),填写以下查找值和替换值

查找值:
// (.*)
替换值:
/**
 * $1
 */

jetbrains官方文档

// 条件值:注意前面有一空格,本示例是查带左小括号的,并且选中`Cc`和`.*`(即大小写和正则)
 ([A-Z])(\w+\()
// 替换值:注意前面有一空格,`\l``\L`转为小写,`\u``\U`转为大写。
 \l$1$2

示例

// 转换前
public String GetName() {}
// 转换后
public String getName() {}
查找值:
(    private .+ )(.+);
替换值:
    @Field("\u$2")
$1$2;

示例

// 替换前
    private String name;
// 替换后
    @Field("Name")
    private String name;

Maven包处理

在打开的项目中,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>
上一篇下一篇

猜你喜欢

热点阅读