常识
swagger 配置文件 曝露接口
blog.csdn.net/Michael_HM/article/details/103998163
input ->PathSelectors.regex("/ins.*").apply(input) ||
PathSelectors.regex("/web/pcMessage.*").apply(input) ||
PathSelectors.regex("/adm/pcMessage.*").apply(input)
获取nacos配置文件
获取简单配置
blog.csdn.net/jike11231/article/details/122866973
kamo:
cloud:
#公网开关true为开,false关
rabbitmq-public-net-on: false
@Value("${kamo.cloud.rabbitmq-public-net-on}")
protected Boolean switchOn;
给其默认值
可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,则会报错。可以通过赋予默认值解决这个问题
@Value("${kamo.cloud.pcrabbitmq-last-days:-7}")
protected Integer days;
//判断ip是否是内网
if (switchOn){
if (!internalIp(getIp2(request))) {
return Result.failed("公网禁止调用");
}
}
@Service注解有什么用?@Service注解的用法?
@Service注解用于类上,标记当前类是一个service类,加上该注解会将当前类自动注入到spring容器中,不需要再在applicationContext.xml文件定义bean了。
用法如下:
在调用该service的时候只需要将该类注入接口中即可:
通过httpClient get请求
CloseableHttpClient aDefault = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("authorization","Basic " + java.util.Base64.getEncoder().encodeToString(author.getBytes()));
response = aDefault.execute(httpGet);
if (response.getStatusLine().getStatusCode() == 200) {
content = EntityUtils.toString(response.getEntity(), "UTF-8");
}
return content;
忽略字段为null的字段
@JsonInclude(JsonInclude.Include.NON_NULL)
如果密码为null 则,直接忽略
lambdaQueryWapper 分页查询,忽略某个字段
i->!i.getProperty().equals(“password”)
lambdaQueryWrapper.select(MessageCenterUserBase.class,i->!i.getProperty().equals("password"));
mybatis 忽略实体对象的某个属性
@TableField(exist = false)
List 去重
- 实体类重写equals
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
MessageCenterMsgTypeBind messageCenterOnline = (MessageCenterMsgTypeBind) obj;
//多重逻辑处理
if (this.getClientId().compareTo(messageCenterOnline.getClientId())==0) {
return true;
}
return false;
}
- 定义该getNoRepeatList方法
public List<MessageCenterAccountBindClient> getNoRepeatList(List<MessageCenterAccountBindClient> oldList) {
List<MessageCenterAccountBindClient> list = new ArrayList<>();
for (MessageCenterAccountBindClient messageCenterOnline : oldList) {
//list去重复,内部重写equals
if (!list.contains(messageCenterOnline)) {
list.add(messageCenterOnline);
}
}
return list;
}
- 调用该方法 getNoRepeatList
List<MessageCenterAccountBindClient> msgList = this.getNoRepeatList(accountList);
获取nacos配置文件
List<SysProperties.Clients> list = new ArrayList<>();
sysProperties.getSys().stream().forEach(t->{ list.addAll(t.getClients()); });
Map<String, SysProperties.Clients> collect = new HashMap<>();
list.forEach(e ->{ collect.put(e.getOpenID(),e); });
PostMapping,gettMapping使用场景
如果传的参数是@RequestBody ,多参或者传对象的情况下使用@PostMapping注解:
@PostMapping(“/getOrderList”)
public List getList(@RequestBody List orderList) {}
无参,@RequestParam 和@PathVaiable的情况下使用GetMapping:
@gettMapping(“/test”)
public ModelAndView test16(@RequestParam(“id”)Long id){}
@gettMapping(“/test/{id}”)
public ModelAndView (@PathVaiable(“name”) Long id){}
ApiOperation
@ApiOperation是Swagger包中的一种注解
使用@ApiOperation注解用来描述我们写的接口。
ApiOperation 注解提供了丰富的属性来允许我们自定义接口描述信息,包括接口名称,接口所属分组等。
接口数据校验验证等
/**
* 用户名密码登录
*/
@LogAnnotation
@DisableClientSecretCheck
@PostMapping("/login")
public Result<Map<String, String>> login(
@Validated({Default.class,
PasswordLoginValidator.class}) @RequestBody LoginVO loginVO) {
SysClientDetails sysClientDetails = clientDetailsInter.selectByClientId(loginVO.getClientId());
if (sysClientDetails == null) {
log.error("web端参数[client_id={}]不正确,请传入正确的clientId", loginVO.getClientId());
return Result
.failedWith(null, PARAM_ERROR.getCode(), PARAM_ERROR.getMsg());
}
/* String password = passwordDecoder.decrypt(loginVO.getPassword());
Principal principal = usernamePasswordAuthenticator
.authenticate(loginVO.getAccount(), password,loginVO);
String at = tokenServiceInter.create(principal);
return Result.succeed(Collections.singletonMap("accessToken", at));
*/
Result result = usernamePasswordAuthenticator
.authenticate(loginVO.getAccount(), loginVO.getPassword(), loginVO);
OAuth2AccessToken oAuth2AccessToken = (OAuth2AccessToken) result.getData();
return Result.succeed(Collections.singletonMap("accessToken", oAuth2AccessToken.getValue()));
}
LoginVO
package com.kamowl.kamo.cloud.personal.open.vo;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import javax.validation.groups.Default;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import static com.kamowl.kamo.cloud.personal.open.constant.RegexpConst.*;
@Data
@Valid
public class LoginVO extends BaseVO {
/**
* 登录账号
*/
@NotBlank(message = "用户名或者密码错误", groups = {Default.class})
@Pattern(regexp = CELLPHONE_REGEX, message = "请输入正确的手机号", groups = {
SmsLoginValidator.class})
@Pattern(regexp = NOT_CHINESE_REGEX, message = "用户名或者密码错误", groups = {
Default.class})
@Size(min = 1, max = 32, message = "用户名必须是1-32位", groups = {
PasswordLoginValidator.class})
private String account;
/**
* 密码
*/
@NotBlank(message = "用户名或者密码错误", groups = {
PasswordLoginValidator.class})
// @Size(min = 300, message = "密码格式不正确", groups = {PasswordLoginValidator.class})
@Pattern(regexp = NOT_CHINESE_REGEX, message = "密码由8-24位数字、字母、符号组成", groups = {
PasswordLoginValidator.class})
private String password;
/**
* 业务系统标识
*/
/* @NotBlank(message = "参数{clientId}不能为空", groups = {Default.class})
@Size(min = 7, max = 10, message = "参数{clientId}为7-10位", groups = {
Default.class})
private String clientId;*/
public interface PasswordLoginValidator {
}
public interface SmsLoginValidator {
}
}
实例
// 要验证的实体类
@Data
public class User implements Serializable {
@NotBlank(message = "id不能为空!",groups = Update.class)
protected String id = "";
@NotBlank(message = "商户id不能为空!")
protected String tenantId;
@NotBlank(message = "名称不能为空!")
protected String name = "";
}
// controller
// 在要验证的参数上添加@Validated注解即可
@PostMapping("add")
public boolean addUser(@Validated @RequestBody User user) {
ProdAllotStandard info = allotStandardService.getProdAllotStandardWithDetailById(id);
return info;
}
// 修改则需要比添加的基础上多验证一个id,可以通过group的方式进行区分
// 实体类上不设置groups,默认会是Default,所以修改的时候,我们需要指定Update和Default这两个组
// group是可以自定义的,我默认定义了Add,Update,Delete,Search这四个组
@PostMapping("update")
public boolean updateUser(@Validated({Update.class, Default.class}) @RequestBody User user) {
ProdAllotStandard info = allotStandardService.getProdAllotStandardWithDetailById(id);
return info;
}
// 当然该注解也支持service上实现,同样的使用方法,在service的实现类的参数上加上对应注解即可,如:
public boolean addUser(@Validated User user) {
}
// 通过不同group的搭配,我们就可以灵活的在实体类上配置不同场景的验证了
// group为一个接口,用以下方式创建
public interface Add {
}
JAVA super 和 this 的作用和区别
super关键字代表的就是“当前对象”的那部分父类型特征。
详细解释
Java String isEmpty() 方法
isEmpty() 方法用于判断字符串是否为空。
如果字符串为空返回 true,否则返回 false。
字符串通过 length() 方法计算字符串长度,如果返回 0,即为空字符串。
public class Main {
public static void main(String[] args) {
String myStr1 = "Runoob";
String myStr2 = ""; // 空字符串
String myStr3 = " "; // 多个空格,length() 不为 0
System.out.println("myStr1 是否为空:" + myStr1.isEmpty());
System.out.println("myStr2 是否为空:" + myStr2.isEmpty());
System.out.println("myStr3 长度:" + myStr3.length());
System.out.println("myStr3 是否为空:" + myStr3.isEmpty());
}
}
Java ArrayList isEmpty() 方法
isEmpty() 方法用于判断动态数组是否为空。
isEmpty() 方法的语法为:
arraylist.isEmpty()
注:arraylist 是 ArrayList 类的一个对象。
参数说明:
无
返回值
如果数组中不存在任何元素,则返回 true。
如果数组中存在元素,则返回 false。
实例
判断动态数组是否为空:
实例
import java.util.ArrayList;
class Main {
public static void main(String[] args){
// 创建一个动态数组
ArrayList<String> sites = new ArrayList<>();
// 检查数组中是否含有元素
boolean result = sites.isEmpty(); // true
System.out.println("sites 是否为空? " + result);
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
System.out.println("网站列表: " + sites);
// 检查该数组是否为空
result = sites.isEmpty(); // false
System.out.println("sites 是否为空? " + result);
}
}
执行以上程序输出结果为:
sites 是否为空? true
网站列表: [Google, Runoob, Taobao]
sites 是否为空? false
@Configuration
proxyBeanMethods 代理bean的方法,如果为true时,无论外部对配置类中的这个组件注册的方法调用多少次获取的都是之前注册到容器的单实例对象,
如果为false, 则不是单例模式,而是重新创建对象
proxyBeanMethods = true 默认是true @Configuration(proxyBeanMethods = true)
@Configuration(proxyBeanMethods = false)
配置类注解,等同于beans.xml文件
@Bean的注解作用
Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。Spring只会调用一次,将这个Bean对象放在自己的IOC容器中。
通俗的将就是在服务启动时,实例化一个对象放到ioc容器中,在需要初始化的实例,方法,内容时使用。
未指定bean 的名称,默认采用的是 “方法名” + "首字母小写"的配置方式
package com.ljf.spring.boot.demo.quartz.config;
import com.ljf.spring.boot.demo.quartz.job.MyDefineQuartz;
import com.ljf.spring.boot.demo.quartz.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
/**
* @ClassName: QuartsConfig
* @Description: TODO
* @Author: liujianfu
* @Date: 2020/07/27 09:13:13
* @Version: V1.0
**/
@Configuration
public class QuartsConfig {
/**
* 1.创建Job对象
*/
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
System.out.println("初始化,创建job对象......");
JobDetailFactoryBean factory = new JobDetailFactoryBean();
//关联我们自己的Job类
factory.setJobClass(MyDefineQuartz.class);
return factory;
}
/**
* 2.Cron Trigger
*/
@Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
System.out.println("初始化,trigger对象......");
CronTriggerFactoryBean factory = new CronTriggerFactoryBean();
factory.setJobDetail(jobDetailFactoryBean.getObject());
//设置触发时间
factory.setCronExpression("0/2 * * * * ?");
return factory;
}
/**
* 3.创建Scheduler对象
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean,User u){
System.out.println("初始化,创建scheduler对象......");
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//关联trigger
factory.setTriggers(cronTriggerFactoryBean.getObject());
System.out.println("初始化u的对象:"+u.getName());
return factory;
}
/**
* @author liujianfu
* @description
* @date 2020/7/27 0027 下午 12:26
* @param []
* @return com.ljf.spring.boot.demo.quartz.model.User
*/
@Bean
public User initUser(){
User u=new User();
u.setId(23);
u.setName("ljf");
return u;
}
}
@Conditinal
条件装配:满足Conditional指定的条件,则进行组件注入
@ConditinalOnMissingClass 容器中没有才添加
@ConditinalOnMissingClass(name=“tom”)
@ConditinalOnBean
容器中是否有该组件,如果有则注入,没有则忽略
可以注册到方法上
可以注册到类上,
@ConditionalOnClass
@ConditionalOnMissBean
@ConditionalOnBean有则注入;@ConditionalOnMissBean没有则注入;@Conditional条件满足则注入。
使用约束:
@ConditionalOnMissingBean注解只作用在@Bean定义的方法上
建议仅仅在自动配置类中使用此注解,虽然放在其他类中也不会报错 该注解仅能匹配已经被当前应用上下文管控的Bean定义
若候选Bean是被其他配置类创建的,需要使用@AutoConfigureBefore
或@AutoConfigureOrder进行配置类先后注入顺序的控制,确保这个条件在其后运行
Condition相关的处理是在包扫描的时候执行的,因此Bean的添加顺序和包扫描的顺序有关,而包扫描的顺序依赖包名和类名的字符排序,同时和maven的pom文件中包引入的顺序也有关系,先引入的包先被扫描到,所以在实际的项目中,我们可以修改类路径或者调整包引入顺序来调整Bean的添加顺序
@AutoConfigureAfter和@AutoConfigureOrder的使用
如果你想将在SpringBoot项目中的配置类进行排序,但在配置@AutoConfigureAfter或者是@AutoConfigureOrder注解之后仍不生效,那么你的项目中应该是缺少了spring.factories文件。因为SpringBoot 只会对从这个文件读取到的配置类进行排序。
@ImportResource 原生配置文件引入
======================beans.xml=========================
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="haha" class="com.atguigu.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.atguigu.boot.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
结果
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);//true
System.out.println("hehe:"+hehe);//true
@Component注解使用详解
@Component注解的作用是什么?
@Component的作用是把普通POJO
① 实例化到Spring容器中,相当于配置文件中的,@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。基于@Component注解有三个扩展,分别是:@Repository 、@Service、 @Controller。被他们四个标注的类,会被纳入到Spring容器中进行管理。除了上面的四个注解外,用户可以创建自定义的注解,然后在自定义的注解上标注 @Component,那么,该自定义注解便具有了与@Component 相同的功能。
@Component注解如何使用?
基于@Component注解有三个扩展,分别是:@Repository 、@Service、 @Controller,他们只是分别具有不同的业务含义,但是被@component 、@Controller 、@Service、@Repository 注解的类,都会把这些类纳入进Spring容器中进行管理。
1、@Component:标注一个普通的POJO实例化到Spring容器中,它是一个通用泛化的注解,当某个组件不能通过业务进行归类时,可以使用这个注解进行标注。
2、@Controller: 用于标注控制层组件。
3、@Service: 用于标注业务层组件。
4、@Repository : 用于标注持久层组件。
注解:
① POJO的名称有多种,pure old java object 、plain ordinary java object 等。 按照Martin Fowler的解释是“Plain Old Java Object”,从字面上翻译为“纯洁老式的java对象”,但大家都使用“简单java对象”来称呼它。
配置绑定
如何使用Java读取到properties文件中的内容,并且把它封装到JavaBean中,以供随时使用;
1、@ConfigurationProperties
/**
* 只有在容器中的组件,才会拥有SpringBoot提供的强大功能
*/
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
2、 @EnableConfigurationProperties + @ConfigurationProperties
3、@Component + @ConfigurationProperties
@EnableConfigurationProperties(Car.class)
//1、开启Car配置绑定功能
//2、把这个Car这个组件自动注册到容器中
public class MyConfig {
}
copyProperties的用法
一、简介:
BeanUtils提供对Java反射和自省API的包装。其主要目的是利用反射机制对JavaBean的属性进行处理。我们知道,一个JavaBean通常包含了大量的属性,很多情况下,对JavaBean的处理导致大量get/set代码堆积,增加了代码长度和阅读代码的难度。
二、用法:
BeanUtils是这个包里比较常用的一个工具类,这里只介绍它的copyProperties()方法。该方法定义如下:
public static void copyProperties(java.lang.Object dest,java.lang.Object orig)
throws java.lang.IllegalAccessException,
java.lang.reflect.InvocationTargetException
如果你有两个具有很多相同属性的JavaBean,一个很常见的情况就是Struts里的PO对象(持久对象)和对应的ActionForm,例如 Teacher和TeacherForm。我们一般会在Action里从ActionForm构造一个PO对象,传统的方式是使用类似下面的语句对属性逐个赋值:
//得到TeacherForm
TeacherForm teacherForm=(TeacherForm)form;
//构造Teacher对象
Teacher teacher=new Teacher();
//赋值
teacher.setName(teacherForm.getName());
teacher.setAge(teacherForm.getAge());
teacher.setGender(teacherForm.getGender());
teacher.setMajor(teacherForm.getMajor());
teacher.setDepartment(teacherForm.getDepartment());
//持久化Teacher对象到数据库
HibernateDAO.save(teacher);
而使用BeanUtils后,代码就大大改观了,如下所示:
//得到TeacherForm
TeacherForm teacherForm=(TeacherForm)form;
//构造Teacher对象
Teacher teacher=new Teacher();
//赋值
BeanUtils.copyProperties(teacher,teacherForm);
//持久化Teacher对象到数据库
HibernateDAO.save(teacher);
如果Teacher和TeacherForm间存在名称不相同的属性,则BeanUtils不对这些属性进行处理,需要程序员手动处理。例如 Teacher包含modifyDate(该属性记录最后修改日期,不需要用户在界面中输入)属性而TeacherForm无此属性,那么在上面代码的 copyProperties()后还要加上一句:
teacher.setModifyDate(new Date());
怎么样,很方便吧!除BeanUtils外还有一个名为PropertyUtils的工具类,它也提供copyProperties()方法,作用与 BeanUtils的同名方法十分相似,主要的区别在于后者提供类型转换功能,即发现两个JavaBean的同名属性为不同类型时,在支持的数据类型范围内进行转换,而前者不支持这个功能,但是速度会更快一些。BeanUtils支持的转换类型如下:
* java.lang.BigDecimal
* java.lang.BigInteger
* boolean and java.lang.Boolean
* byte and java.lang.Byte
* char and java.lang.Character
* java.lang.Class
* double and java.lang.Double
* float and java.lang.Float
* int and java.lang.Integer
* long and java.lang.Long
* short and java.lang.Short
* java.lang.String
* java.sql.Date
* java.sql.Time
* java.sql.Timestamp
这里要注意一点,java.util.Date是不被支持的,而它的子类java.sql.Date是被支持的。因此如果对象包含时间类型的属性,且希望被转换的时候,一定要使用java.sql.Date类型。否则在转换时会提示argument mistype异常。
三、优缺点:
Apache Jakarta Commons项目非常有用。我曾在许多不同的项目上或直接或间接地使用各种流行的commons组件。其中的一个强大的组件就是BeanUtils。我 将说明如何使用BeanUtils将local实体bean转换为对应的value 对象:
BeanUtils.copyProperties(aValue, aLocal)
上面的代码从aLocal对象复制属性到aValue对象。它相当简单!它不管local(或对应的value)对象有多少个属性,只管进行复制。我们假设 local对象有100个属性。上面的代码使我们可以无需键入至少100行的冗长、容易出错和反复的get和set方法调用。这太棒了!太强大了!太有用 了!
现在,还有一个坏消息:使用BeanUtils的成本惊人地昂贵!我做了一个简单的测试,BeanUtils所花费的时间要超过取数 据、将其复制到对应的 value对象(通过手动调用get和set方法),以及通过串行化将其返回到远程的客户机的时间总和。所以要小心使用这种威力!
执行这个方法牵扯到类型转换时要注意的问题:
有关BeanUtils的copyProperties
BeanUtils是org.apache.commons的一个很重要的包,主要提供一些对Bean的操作。这个类我很早就接触了,大概是再2年多以前。当时还是大家在疯狂讨论J2EE每个层次是否都应该拥有各自的Object,并是否需要在这些Object之间进行互相转化的年代。而当时,有很多激进派都坚决主张引入DTO或者VO(事实上这是一种反模式),他们的观点很简单,每个层次含义不同,对应运行的Object也应该不同,而他们之间的转化,由BeanUtils来做是相当简单的,一句话就可以了。
当时对这种转化的言论我没有发表任何议论,因为领悟不深。但是对于BeanUtils这个有用的类,倒是一直在使用,因为他比较简单。一个静态方法,使用反射,马上就可以复制一个Bean出来。当时脑子里面一闪而过的印象只是,这样的copy肯定比我手工一个一个copy的效率低,因为他用了反射。不过反射能差多少效率呢?Spring不是通篇用了反射嘛?因而更加细一步的内容和源码也没有自己探究。
直到两年后的今天,没想到这个BeanUtils的copyProperties方法却给我带来了极大的麻烦。请看下面的testCase:
/**
*
*@throwsException
*/
publicvoid testBeanUtilsCopyProperties()throws Exception {
Admin admin = new Admin();
User user = new User();
user.setId(new Long(1));
user.setName("downpour");
user.setRate(new Double(1));
logger.info("before copy:");
logger.info("admin id:" + admin.getId());
logger.info("admin name:" + admin.getName());
logger.info("admin password:" + (admin.getPassword() == null));
logger.info("admin birthday:" + admin.getBirthday());
logger.info("admin mark:" + admin.getMark());
logger.info("admin sex:" + admin.getSex());
BeanUtils.copyProperties(admin, user);
logger.info("after copy:");
logger.info("admin id:" + admin.getId());
logger.info("admin name:" + admin.getName());
logger.info("admin password:" + (admin.getPassword() == null));
logger.info("admin birthday:" + admin.getBirthday());
logger.info("admin mark:" + admin.getMark());
logger.info("admin sex:" + admin.getSex());
}
其中,admin和user分别拥有共有的字段:id(java.lang.Long),name(java.lang.String),password(java.lang.String),birthday(java.util.Date),sex(java.lang.Integer)。然后我运行上面的TestCase,在User中,我特地没有给sex这个字段赋值,让他的值为null。运行的结果却让我郁闷:
09:20:24,221 INFO BeanUtilsTest:49 - before copy:
09:20:24,221 INFO BeanUtilsTest:50 - admin id:null
09:20:24,221 INFO BeanUtilsTest:51 - admin name:null
09:20:24,221 INFO BeanUtilsTest:52 - admin password:true
09:20:24,231 INFO BeanUtilsTest:53 - admin birthday:null
09:20:24,231 INFO BeanUtilsTest:54 - admin mark:null
09:20:24,231 INFO BeanUtilsTest:55 - admin sex:null
09:20:24,291 INFO BeanUtilsTest:59 - after copy:
09:20:24,291 INFO BeanUtilsTest:60 - admin id:1
09:20:24,301 INFO BeanUtilsTest:61 - admin name:downpour
09:20:24,301 INFO BeanUtilsTest:62 - admin password:true
09:20:24,301 INFO BeanUtilsTest:63 - admin birthday:null
09:20:24,301 INFO BeanUtilsTest:64 - admin mark:null
09:20:24,301 INFO BeanUtilsTest:65 - admin sex:0
注意最后一行,明明没有给User赋值,做了一次copy,却带入了一个0到新的Admin中去。这不是强买强卖嘛?而且我特地用了java.lang.Integer的外覆类,那应该他是null,你就copy一个null过去呗,没事情你给我初始化一下做啥?汗~~~
后来看了源码,才发现,原来是类型转化惹的祸。由于在BeanUtils中,隐含了一个对于不同类型之间进行转化的步骤。也就是说,如果你的Source Bean中某个字段原本是String,而Dest Bean中的对应字段是Integer,它在可以进行转化时可以帮你做自动的转化。在这个转化中,会在中间变量中都先new一个default值set进去。昏过去。。。
看来这个方法在做copy时实在是不安全,尤其是对于那些null值本身有含义的情况下,只能舍弃这个方法。幸好,apache还有点人性,提供了一个叫做PropertyUtils的copyProperties方法。这个方法不会去做相应的类型转化。可以放心使用,不过如果你的Bean的类型不匹配,那么它会报错。
//初始化空List
List<UserWalletDetailVo> list = Collections.emptyList();
spring:
application:
name: kamo-cloud-financial-center
cloud:
inetutils:
preferred-networks: 192.168.11
mybits 用实体类只返回需要的数据
mybits 用实体类只返回需要的数据
<select id="findOilWalletRecordDetailByTime" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from prepay_oil_record_detail
where DATE_FORMAT(create_time,'%Y-%m-%d %H:%i:%s') >= #{recordStartTime}
and #{recordEndTime} > DATE_FORMAT(create_time,'%Y-%m-%d %H:%i:%s')
order by id asc
</select>
通用查询结果列
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, parent_record_no,net_id, receod_no, change_type, trade_id, owner_id, driver_id, driver_name, side_role, parent_type, owner_phone, owner_name, main_role, operate_type, driver_mobile, vehicle_no, before_money, amount, after_money, create_time, operate_user_name, operate_user_id, order_no, cert_pic, trade_driver_id, trade_driver_phone, trade_driver_name, canal, remark, send_address, receive_address
</sql>
通用映射类
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.kamowl.kamo.cloud.financial.open.model.PrepayOilRecordDetail">
<id column="id" property="id" />
<result column="parent_record_no" property="parentRecordNo" />
<result column="receod_no" property="receodNo" />
<result column="change_type" property="changeType" />
<result column="net_id" property="netId" />
<result column="trade_id" property="tradeId" />
<result column="owner_id" property="ownerId" />
<result column="driver_id" property="driverId" />
<result column="driver_name" property="driverName" />
<result column="side_role" property="sideRole" />
<result column="parent_type" property="parentType" />
<result column="owner_phone" property="ownerPhone" />
<result column="owner_name" property="ownerName" />
<result column="main_role" property="mainRole" />
<result column="operate_type" property="operateType" />
<result column="driver_mobile" property="driverMobile" />
<result column="vehicle_no" property="vehicleNo" />
<result column="before_money" property="beforeMoney" />
<result column="amount" property="amount" />
<result column="after_money" property="afterMoney" />
<result column="create_time" property="createTime" />
<result column="operate_user_name" property="operateUserName" />
<result column="operate_user_id" property="operateUserId" />
<result column="order_no" property="orderNo" />
<result column="cert_pic" property="certPic" />
<result column="trade_driver_id" property="tradeDriverId" />
<result column="trade_driver_phone" property="tradeDriverPhone" />
<result column="trade_driver_name" property="tradeDriverName" />
<result column="canal" property="canal" />
<result column="remark" property="remark" />
<result column="send_address" property="sendAddress" />
<result column="receive_address" property="receiveAddress" />
</resultMap>
批量查询
如果Integer[] ids 是 List<Integer> ids则无需CollUtil.newArrayList(ids)
@GetMapping(value = "/users-anon/ids")
@ApiOperation(value = "根据用户ID列表查询用户")
@ApiIgnore
@LogAnnotation
public Result<List<SysUser>> findByUserIds(@RequestParam Integer[] ids) throws ControllerException {
try {
return Result.succeed(sysUserService.findByIds(CollUtil.newArrayList(ids)));
} catch (ServiceException e) {
throw new ControllerException(e);
}
}
@Override
public List<SysUser> findByIds(List<Integer> ids) throws ServiceException {
try {
if (ids == null || ids.isEmpty()) {
return new ArrayList<>();
}
QueryWrapper<SysUser> userWrapper = new QueryWrapper<>();
userWrapper.in("id", ids);
return sysUserDao.selectList(userWrapper);
} catch (Exception e) {
throw new ServiceException(e);
}
}
//mybits 批量查询
select * from (
select * from sys_state_oil_station_net
where count_time_int <= #{dataTime}
and user_id in
<foreach item="item" index="index" collection="userIds"
open="(" separator="," close=")">
#{item}
</foreach>
ORDER BY count_time desc
) s1
GROUP BY user_id
调用
findByUserIds(userIds.parallelStream().toArray(Integer[]::new))
把List 转 Map 操作
原来需要循环遍历
Map<String, String> map = new HashMap<>();
for (User user : userList) {
map.put(user.getId(), user.getName());
}
现在
java8之后我们就可以用stream来操作集合了
假如用stream流新特性来做就一行代码
userList.stream().collect(Collectors.toMap(User::getId, User::getName));
如果希望得到 Map 的 value 为对象本身时,可以这样写:
userList.stream().collect(Collectors.toMap(User::getId, Function.identity()));
userInfos.getData().parallelStream().collect(Collectors.toMap(SysUser::getId, Function.identity(), (key1, key2) -> key2));
toMap(参数1,参数2,参数3)
参数1:作为map的key值
参数2:Function.identity() (v->v 相同的意思)表示选择原有的对象作为map的value的值
参数3:(key1, key2) -> key2) 如果key1和key2的值相同,选择key2作为那个key所对应的value值
如何把List 组装成 Map<Integer, List>
List 组装成 Map<Integer, List>
public Result<Map<Integer, List<SysRole>>> findRolesByUserIds(List<Integer> userIds) {
try {
Map<Integer, List<SysRole>> map = new HashMap<>();
if (userIds != null && !userIds.isEmpty()) {
List<SysRole> sysRoles = userRoleDao.findRolesByUserIds(userIds);
for (SysRole sysRole : sysRoles) {
List<SysRole> list = map.get(sysRole.getUserId());
if (list == null) {
list = new ArrayList<>();
}
list.add(sysRole);
map.put(sysRole.getUserId(), list);
}
}
return Result.succeed(map);
} catch (Exception e) {
throw new ServiceException(e);
}
}
判断 List集合是否为空
if(CollectionUtil.isEmpty(roles)){
return false;
}
判断是否为true
private boolean userBelongRole(List<SysRole> roles,String roleCode){
if(CollectionUtil.isEmpty(roles)){
return false;
}
Set<String> roleCodeSet=roles.stream().map(SysRole :: getCode).collect(Collectors.toSet());
if(roleCodeSet.contains(roleCode)){
return true;
}
return false;
}