问题总结(1-34) 备注:很多摘抄于博客
目录:
- url重写
2. Logger logger = LoggerFactory.getLogger()为什么会出异常?
3. 在继承于HTTPServlet的类中使用Logger logger = LoggerFactory.getLogger()为什么会出异常?
4. log4j在多线程环境下第一次打印一次,第二次重复打印两次…,问题
5. 更改SpringBoot内置tomcat容器默认端口
6. SpringBoot报 Whitelabel Error Page错误
7. SpringBoot无法通过autowired注解注入repository对象
8. log4j:ERROR Could not find value for key log4j.appender.debug错误
9. SpringBoot事务注解@Transactional 事物回滚、手动回滚事物
10. 什么是“容器编排”
11. SpringBoot怎么从配置文件中读取相应属性值
12. Springboot采用从配置文件中读取mapping路径时,若MockMvc的单元测试采用的是独立测试环境,则单元测试代码会出错
13. Springboot的注解@Controller和@RestController有什么区别
14. Sprng注解@ReuqestMapping详解
15. Springboot的定时任务@Scheduled 三个参数fixedRate,fixedDelay,cron的不同
16. 什么是Restful
17. lombok使用
18. 怎么在Intellij中查看某接口的实现类的源码
19. Intellij怎么改项目名称
20. 将log4j.properties的路径写为相对路径
21. mysql中更新时间和创建时间的自动更新
22. mysql删除表中数据
23. mysql修改表结构
24. mysql的timestamp类型的一些注意点
25. springboot返回json格式数据
26. SpringBoot controller类方法接收@Requestbody形式参数,并用postman测试
27. Springboot CrudRepository和JpaRepository的区别
28. Jpa自定义查询报错(Failed to convert from type [java.lang.Object[]] to type)
29. 在使用 Spring Data JPA 时遇到报错:No converter found capable of converting from type [java.lang.Integer] to type [com.wchat.bean.Group]
30. JPA 的Encountered a duplicated sql alias [id] during auto-discovery of a native-sq异常。
31. MySql 为表中已有字段设置默认值
32. Spring 进入Controller前参数校验
33. @ControllerAdvice注解的三种使用场景
34. SpringBoot 使用props类和@ConfigurationProperties注解和@PropertySource注解来读取配置文件的内容
1. url重写
把JSESSIONID从客户端传到服务器端有两种方式:
①JESESSIONID保存在cookie文件中,浏览器发送请求的时候把这个cookie文件中的数据带给服务器(cookie)。
②通过传参的方式,把JSESSIONID的值通过要访问的URL传给服务器.(URL重写)。
2. Logger logger = LoggerFactory.getLogger()为什么会出异常?
没有加载到配置文件,见4点。
3.在继承于HTTPServlet的类中使用Logger logger = LoggerFactory.getLogger()为什么会出异常?
maven添加了相关jar包的依赖,并且已经下载了相关的jar包,在Itellij的External Libraries中也可以找到相关jar包,但启动tomcat容器后,还是显示找不到相关的jar包。
原因:是因为maven管理的jar包没有添加到相应容器中。
解决:以Intellij为例,将maven管理的jar包添加到相应容器中。
①右键项目,点击Open Module Settings
②选择左侧的Artifacts,如图,所有操作更改记得点击Apply
4. log4j在多线程环境下第一次打印一次,第二次重复打印两次…,问题
log4j,slf4j 在运用了BasicConfigurator.configure()后,在多线程环境中,第一次输出1次重复语句,第二次输出2次重复语句,第三次输出3次重复语句,…,的问题。
原因:当遇到如下报错时,
log4j:WARN No appenders could be found for logger (Ch06.Array).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http:// logging.apache.org/log4 j/1.2/faq.html#noconfig for more info.
说明log4j.properties配置文件没有被读取,此时如果使用BasicConfigurator.configure()设置缺醒环境,虽然可以使用log4j
但它会给根记录器增加一个ConsoleAppender,默认级别为LEVEL.DEBUG
,因此就出现了上述问题。
应该使用PropertyConfigurator.configure("D:\\project\\src\\log4j.properties");
configure()中传log4j.properties的绝对路径,比如此处的"D:\\project\\src\\log4j.properties"。
5. 更改SpringBoot内置tomcat容器默认端口
在应用的application.properties或者yml配置文件中,添加配置项。
如:
6. SpringBoot报 Whitelabel Error Page错误
见 https://www. cnblogs.com/williamjie/ p/9199586.html
是因为controller.java文件放的位置不对,程序只加载Application.java所在包及其子包下的内容。
解决方法一:将包目录改成正确的
解决方法二:
在Application类中加上@ComponentScan(basePackages = {"com.demo.controller"}) 多个之间用","分隔。其中,com.demo.controller是你的controller所在的包。如下图:
7. SpringBoot无法通过autowired注解注入repository对象
这其实也是启动类application.java的文件位置的问题,与问题6的原因一样。但是这儿通过问题6中的方法二的@ComponentScan注解无法解决,正确的方法是应该让文件目录正确。检查repository对象注解失败的步骤如下:
①SpringBoot的启动类application一定要放在所有注入包的上面,最好是所有java包都是启动类所在包的子包,springboot启动扫描默认扫描启动类所在包和子包,如果将启动类放置在了底包,那么将扫描不到有些包,造成注入失败。
正确的目录结构如下:
②确保注解已经加上,control层加@RestController或@Controller注解,service层加@Service注解,dao层加上@Repository注解,实体类加上@Entity和@Table注解(如果类名和表名一致可以省略),在id上加@Id注解,并指明id的增长策略,变量加上@Colum注解(如果字段和变量一致可以省略)。
③确保pom文件依赖引入的正确性。我的就是此问题,一不小心引入了Spring-JPA 的依赖,应该引入springboot-starter的JPA依赖。
8. log4j:ERROR Could not find value for key log4j.appender.debug错误
这个问题在用PropertyConfigurator.configure初始化配置文件后仍然无法解决的情况下,引起此错误的原因可能是配置文件log4j.properties写的不对。比如我的配置文件如下所示:
log4j.rootLogger=stdout
# 输出到控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %p [%t] %C.%M(%L) | %m%n
这个配置文件可以运行,因为蓝色部分完全对应起来。也就是说,在log4j.rootLogger中定义了什么级别(比如此处的stdout),在下面 http:// log4j.appender.xxx 的配置中就要有该级别的appender的配置。
如果用下面这样的log4j.properties:
log4j.rootLogger=stdout,INFO
# 输出到控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %p [%t] %C.%M(%L) | %m%n
就会报错:
log4j:ERROR Could not find value for key http:// log4j.appender.INFO
log4j:ERROR Could not instantiate appender named "INFO".
log4j:ERROR Could not find value for key http:// log4j.appender.INFO
log4j:ERROR Could not instantiate appender named "INFO".
因为log4j.rootLogger中的INFO在log4j.appender中找不到相对应的。
9. SpringBoot事务注解@Transactional 事物回滚、手动回滚事物
spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作(对非检查型类异常可以不用捕获,而检查型异常则必须用try语句块进行处理或者把异常交给上级方法处理)。
在spring的事务管理环境下,使用unchecked exception可以极大地简化异常的处理,只需要在事务层声明可能抛出的异常(这里的异常可以是自定义的unchecked exception体系),在所有的中间层都只是需要简单throws即可,不需要捕捉和处理,直接到最高层,比如UI层再进行异常的捕捉和处理。
默认规则:
让checked异常回滚: @Transactional(rollbackFor=Exception.class),一般只需添加这个即可
让unchecked异常不回滚: @Transactional(notRollbackFor=RunTimeException.class)
不需要事务管理的(只查询的)方法: @Transactional(propagation=Propagation.NOT_SUPPORTED),或者不添加
10. 什么是“容器编排”
应用一般由单独容器化的组件(通常称为微服务)组成,且必须按顺序在网络级别进行组织,以使其能够按照计划运行。以这种方法对多个容器进行组织的流程即称为容器编排。所有的容器编排引擎均可让用户控制容器启动和停止的时间、将其分组合到群集中,以及协调应用组合的流程。容器编排工具允许用户指导容器部署与自动更新、运行状况监控以及故障转移等步骤。
11. SpringBoot怎么从配置文件中读取相应属性值
背景是:在SpringBoot开发中,以前自己写mapping的路径时总是直接写在里面,如下图所示:
但是实际项目开发中,mapping的路径要从properties配置文件中读取
①在application.properties配置文件中,定义属性值。在controller中读取。
application.properties文件中的内容如下:
controller如下:
这种方法可以很好解决背景中的问题,但是要注意的是如果采用从配置文件中读取路径的方式,而单元测试又采用的是MocMvc的独立测试环境来测试的话,单元测试程序会出错,这一点在下面叙述。
②在application.properties中有:
读取时,如下:
定义一个类的属性, 通过@Value(“${properties.path}”)来读取,其中properties.path是properties 自定义属性值的属性名。
③采用自定义配置文件的方式
a. 添加pom依赖
<!-- springboot configuration依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId> spring-boot-configuration-processor</artifactId>
<optional> true </optional>
</dependency>
b. 在resources下建一个config的directionary(名字人去), 在config里建一个remote.properties(properties文件的文件名任取)。
c. 在配置文件中写入测试内容
d. 写一个实体类,属性与配置文件对应
不适用lombok插件的话,要自己手动写get、set方法和构造函数等。
e. 读取
但是要注意的是如果在@RequestMapping(remoteProperties.getTestname()) 的方式来代替@Request Mapping(”testProperties”),程序会报错,原因还不明白,觉得可能是remoteProperties.getTestname()可能得到空值,所以这种写法被spring禁止。
12. Springboot采用从配置文件中读取mapping路径时,若MockMvc的单元测试采用的是独立测试环境,则单元测试代码会出错
采用MockMvc的独立测试环境进行springboot接口的单元测试的代码如下:
controller的代码如下:
单元测试代码如下:
其中在setup()方法中的 mockMvc = MockMvcBuilders.standaloneSetup(peopleController).build() 就是采用独立测试环境进行单元测试。
当采用从配置文件中读取mapping路径的方式时,
controller的代码如下:
若还是采用上述独立测试环境进行测试的话,会出错,出错的原因在于,虽然peopleController正常注入了不为null,但是通过MockMvcBuilders.standaloneSetup(peopleController).build()得到的MockMvc对象为null。
自己觉得原因是采用独立测试环境进行单元测试时,程序没有从properties配置文件中读取相应值。
解决方法如下:
核心点在于:改变MockMvc对象的生成方式。在单元测试类上加上@AutoConfigureMockMvc注解,然后通过
注解生成MockMvc对象。
13. Springboot的注解@Controller和@RestController有什么区别
@RestController注解相当于@ResponseBody + @Controller合在一起的作用。
①使用@Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面,若返回json等内容到页面,则需要加@ResponseBody注解。
②@RestController注解,相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面。
14. Sprng注解@ReuqestMapping详解
(1) @RequestMapping的value属性和path属性
这两个属性作用相同,可以互换,如果仅有这一个属性,则可以省略,下面两个例子均采用省略的方式。
①将@RequestMapping注解在login方法上,而UserController上不添加 @RequestMapping 注解,这时的请求 URL 是相对于 Web 根目录。
@Controller
public class UserController {
@RequestMapping("/login")
public String login() {
return "success";
}
}
此时接口地址应该为: http:// localhost/SpringMVC/log in
②将 @RequestMapping 注解在 UserController 类上,这时类的注解是相对于 Web 根目录,而方法上的是相对于类上的路径。
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")
public String login() {
return "success";
}
}
此时请求路径为: http:// localhost/SpringMVC/use r/login
(2) @RequestMapping 的 method 属性
①RequestMapping的method属性指定Get请求方式
@RequestMapping(path = "/login", method=RequestMethod.GET)
②RequestMapping的method属性指定Post请求方式
@RequestMapping(path = "/login", method=RequestMethod.POST)
③RequestMapping的method属性指定多种类型的请求方式
@RequestMapping(path = "/login", method={RequestMethod.POST,RequestMethod.GET})
(3) @RequestMapping 的 params 属性
该属性表示请求参数,也就是追加在URL上的键值对,多个请求参数以&隔开。
@RequestMapping(path = "/login", params={"username=kolbe","password=123456"})
该方法将接收 /user/login 发来的请求,且请求参数必须为username=kolbe&password=123456。
(4) @RequestMapping 的 headers 属性
该属性表示请求头
@RequestMapping(path = "/login", headers="Host=localhost:8080")
表示只接收本机发来的请求
15. Springboot的定时任务@Scheduled 三个参数fixedRate,fixedDelay,cron的不同
fixedRate: 每隔多少秒执行一次任务
fixedDelay:前一个任务结束多少秒后开始执行任务
cron:当时间达到设置的时间会触发事件,比如@Scheduled(cron="0/5 * * * *?"),5秒执行一次
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class MyProcessor{
DateFormat sdf = new SimpleDateFormat("HH:mm:ss");
int[] delays = new int[]{8,3,6,2,2};
int index = 0;
@Scheduled(cron = "0/5 * * * * ?}")
public void process() {
try {
if(index > delays.length - 1){
if(index == delays.length){
System.out.println("---------- test end at " + sdf.format(new Date()) + " ---------");
index ++;
return;
}else{
System.out.println(index + ":start run at" + sdf.format(new Date()));
Thread.sleep(delays[index] * 1000);
System.out.println(index + ":end run at " + sdf.format(new Date()));
index ++;
} catch (InterruptedException e) {
e.printStackTrace();
简要说明上述代码含义:
上述代码假定Scheduled的任务序列如下:
任务编号 | 耗时(单位:秒) |
0 | 8 |
1 | 3 |
2 | 6 |
3 | 2 |
4 | 2 |
分别使用下述三种参数:
@Scheduled(cron = "0/5 * * * * ?}") :5秒执行一次
@Scheduled(fixedDelay = 3000) :上次任务结束3秒后开始执行
@Scheduled(fixedRate = 5000) :每隔5秒开始执行
@Scheduled(cron = "0/5 * * * * ?}")的执行结果如下图:
从结果可以看出,使用了cron参数的时间轮转片总为5秒,第一个任务需要8秒执行完,
第一个5秒后发现任务仍然在执行,在第二个5秒中的第三秒,任务结束,此时还需等待2秒,等第二个5秒执行完,再开始新的任务。后续类似。比如任务2耗时6秒,待第一个5秒过后,第二个5秒中运行了1秒任务结束,此时需将第二个5秒的时间流转片运行完,故还要等待4秒,再开启新任务(任务3)