Springboot @value 注解注入静态属性
1 |
|
直接在属性上使用 @value
是无效的,要通过 set
方法注入, class
要加上 @Component
注解
mybatis-plus简称MP是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网 。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。
下面是在MP
为基础封装了一个查询类,实现了如果需要增加查询条件只需在前端修改即可。
1 | public class SearchModel<T> { |
1 | public class Field { |
1 | public enum QueryMethod { |
1 | { |
在api中传入上面的json对象即可完成一个查询服务,查询条件通过前端传入的字段控制
IBaseService
1 |
|
BaseServiceImpl
1 | public class BaseServiceImpl<M extends BaseMapper<T>, T> implements IBaseService<T> { |
MP实现了mapper层基础的CRUD方法,这里把一些常用的service层的方法整理了一下,又减少了一些代码量
为了项目的正常运行中,异常捕获,记录也是非常重要的,方便我们排查问题,定位问题
为了方便定位异常,自定义了几种异常类,方便我们快速定位异常。
1 | public class HttpException extends RuntimeException { |
1 | public class ParameterException extends HttpException { |
1 | public class ServerErrorException extends HttpException { |
1 | public class UnAuthenticatedException extends HttpException{ |
1 | public class ForbiddenException extends HttpException { |
1 | public class NotFoundException extends HttpException { |
这里定义了我在项目中常用的几种异常,也可根据实际情况定义自己所需的异常。
捕获异常需要用到一个注解@ControllerAdvice
,关于它的详细解释可查看文档。
使用方法如下,定义一个异常捕获类
1 | @ControllerAdvice |
这个类就已经实现了捕获全局异常的功能,下面在加上上面定义的几种异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31@ControllerAdvice
public class GlobalExceptionAdvice {
@ExceptionHandler(UnAuthenticatedException.class)
public ResponseEntity unAuthenticatedException(UnAuthenticatedException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getCode());
}
@ExceptionHandler(ParameterException.class)
public ResponseEntity handleParameterException(ParameterException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getCode());
}
@ExceptionHandler(ForbiddenException.class)
public ResponseEntity handleForbiddenException(ForbiddenException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getCode());
}
@ExceptionHandler(NotFoundException.class)
public ResponseEntity handleNotFoundException(NotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getCode());
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity handleRunTimeException(RuntimeException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(500);
}
}
@ExceptionHandler
注解表示该方法捕获的异常类型,就可以在不同的异常中进行不同的处理方式。
捕获到异常之后我们要记录下来,方便我们对bug的追踪解决。
记录方法有多种多样的,比如记录到数据库或者log
文件中。我使用了第二种方式。
1 | <dependency> |
logback.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 <?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台 appender, 几乎是默认的配置 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<!-- 输出的日志文本格式, 其他的 appender 与之相同 -->
<pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- info 级别的 appender -->
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志写入的文件名, 可以是相对目录, 也可以是绝对目录, 如果上级目录不存在会自动创建 -->
<file>./logs/info/log-stack.log</file>
<!-- 如果是 true, 日志被追加到文件结尾; 如果是 false, 清空现存文件. 默认是true -->
<append>true</append>
<!-- 日志级别过滤器, 只打 INFO 级别的日志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<!-- 下面2个属性表示: 匹配 level 的接受打印, 不匹配的拒绝打印 -->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 最常用的滚动策略, 它根据时间来制定滚动策略, 既负责滚动也负责触发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 设置滚动文件规则, 如果直接使用 %d, 默认格式是 yyyy-MM-dd -->
<fileNamePattern>./logs/info/log-stack.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保留14天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 定义日志输出格式 -->
<encoder charset="UTF-8">
<pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- error 级别的 appender -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./logs/error/log-stack.log</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>./logs/error/log-stack.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保留7天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 定义日志输出格式 -->
<encoder charset="UTF-8">
<pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- error 级别的 appender -->
<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./logs/debug/log-stack.log</file>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>./logs/debug/log-stack.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保留7天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 定义日志输出格式 -->
<encoder charset="UTF-8">
<pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 指定 com.github 下的日志打印级别, appender -->
<logger name="com.github" level="debug" additivity="false">
<appender-ref ref="stdout"/>
<appender-ref ref="info"/>
<appender-ref ref="error"/>
<appender-ref ref="debug"/>
</logger>
<root level="info">
<appender-ref ref="stdout"/>
<appender-ref ref="info"/>
<appender-ref ref="error"/>
</root>
</configuration>
1 | @ControllerAdvice |
文章中的异常只定义了code
,具体的异常信息可以写在配置文件中或者保存在数据库中,在捕获到异常之后,找到对应的描述信息返回调用者,增加友好度。
以上如果发生了异常,在日志文件中是这样记录的
1 | 10:19:32.024 [http-nio-8080-exec-2] ERROR c.g.e.d.advice.GlobalExceptionAdvice 41 - / by zero |
发现记录的行号是在GlobalExceptionAdvice
类中,并非是代码真实的位置。
如果要记录到代码的真实位置可以这样实现
1 | public String getExceptionDetail(Exception e) { |
1 | log.error(getExceptionDetail(e)); |
根据实际情况选择适合自己的方式
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
npm
初始化项目1 | $ mkdir es6-to-es5 |
1 | $ npm install --save-dev @babel/core @babel/cli |
安装完成之后, 你的 package.json
会加入这些代码
1 | "devDependencies": { |
现在把 Babel
的运行命令放入到 npm
脚本中, 也是在 package.json
中
1 | "scripts": { |
1 | $ npm install @babel/preset-env --save-dev |
创建babel.config.json
文件,写入以下内容
1 | { |
环境都配置完成, 下面开始正式写代码了
创建 /src/index.js
1 | $ mkdir src |
写入一个简单的箭头函数
1 | let sayHello = () => { |
现在运行刚刚写好的启动脚本
1 | $ npm run build |
完成之后可以看到目录中新增了一个build
文件夹,打开里面的index.js
它的内容是这样的
1 | "use strict"; |
现在执行下面的命令
1 | $ node build/index.js |
可以正常的输出,到现在好像已经可以正常的使用了
点击获取源码
nvm
安装1 | $ wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash |
提示内容:
=> Downloading nvm as script to ‘/home/dhbm/.nvm’
=> Appending nvm source string to /home/dhbm/.bashrc
=> Appending bash_completion source string to /home/dhbm/.bashrc
=> Close and reopen your terminal to start using nvm or run the following to use it now:
export NVM_DIR=”$HOME/.nvm”
[ -s “$NVM_DIR/nvm.sh” ] && . “$NVM_DIR/nvm.sh” # This loads nvm
[ -s “$NVM_DIR/bash_completion” ] && . “$NVM_DIR/bash_completion” # This loads nvm bash_completion
按照提示,直接 copy 粘贴以上内容
1 | export NVM_DIR="$HOME/.nvm" |
1 | $ nvm install node # 安装nodejs |
开发环境设置
上一章在日常开发的过程中,debug是避免不了的,我们都知道webpack
是把文件打包了的,对于debug
来说是非常不方便的,本章主要说一下怎么debug
1 | module.exports = { |
把这行代码注释掉
在src
目录下新增一个名为Person.ts
的文件,内容如下
之前的代码全部注释或删除,新增以下内容
内容准备完成,现在来启动项目实践debug
执行yarn start
现在开始调试项目
启动之后我们会发现在终端中会出现这样一个提示,出现这个提示的原因是因为我们在第一步修改的webpack.config.js
文件,webpack
不知道该以什么模式启动项目了。mode
的类型有两个,分别是development
和production
,分别代表开会环境和正式环境。稍后在进行配置。
接下来打开浏览器会看到控制台
我们在调用方法的时候传入的参数是undefined
,所以报这个错了,我们也知道怎么去改,可是在开发项目的过程中不可能每一个地方都记得特别清楚,我们是需要控制台去精准的提示给我们是哪里报凑了,从上图中我们可以看到是main.js
文件的第2行报的错,我们点击它定位到错误位置。
出现在眼前的是这一行压缩的代码,它是打包过的代码,是不利于调试的。我们要使用devtool
来解决这个问题
选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。
devtool
其实就是选择对应的source map
,它有很多种,现在来看一下每种都有什么区别。
这种是比较常见的,设置方法就是在webpack.config.js
中修改这个属性,代码如下
1 | module.exports = { |
设置完成之后启动项目看一下效果
精确的提示除了出错的文件和行数,方便我们准确的定位,那webpack究竟是做了什么呢。
打包后的模块在最下面引用一个map文件,map文件就是打包后的文件和源文件之间的一个关联文件,里面记录着编译后的代码对应着源码中的位置
使用inline
,webpack
不会生成独立的map
文件,而是将map
文件内容以dataURL
的形式插入到打包的文件中
cheap-source-map
它与source-map
一样也是会生成独立的map
文件,不同的是它不包含源代码中的列信息
module-source-map
生成的map
文件中还包含引用的一些第三方库
不同环境的配置使用,建议参考官方文档,只有官方文档才是最新最准确的
1 | $ mkdir -p /etc/nginx/ssl |
注意要加过期时间,默认的有效期很短
1 | $ cd /etc/nginx/conf.d |
输入以下内容
1 | server { |
保存退出并重启nginx
因为我们的证书没有给相关机构认证,所以还是提示不安全,但是不影响我们测试使用
如果想部署个人服务器的话可以在各大服务器厂商申请免费的ssl证书,也是很方便的,前提是要有自己的域名。
我是在腾讯云申请的免费ssl
证书。按照官网的提示操作很简单的。
1 | $ sudo yum install -y epel-release |
安装成功后,默认的网站目录为: /usr/share/nginx/html
默认的配置文件为:/etc/nginx/nginx.conf
自定义配置文件目录为: /etc/nginx/conf.d/
1 | $ sudo firewall-cmd --permanent --zone=public --add-service=http |
开启80和443端口
启动Nginx
1
$ systemctl start nginx
停止Nginx
1 | $ systemctl stop nginx |
重启Nginx
1
$ systemctl restart nginx
查看Nginx状态
1 | systemctl status nginx |
设置开机启动
1
$ systemctl enable nginx
禁止开机启动
1 | $ systemctl disable nginx |
1 | upstream tomcats { |
1 | server { |
1 | proxy_cache_path /opt/app/cache levels=1:2 |
你现在使用的输入法具体是什么?另外你是用 ibus 的吗?
在启动文件中输入
1 | export XMODIFIERS="@im=ibus" |
然后启动 WebStorm 试试。
如果不行的话,你再换成下面的试试。
1 | export GTK_IM_MODULE=fcitx |
如果还不能解决,参考下面的链接操作一下
https://youtrack.jetbrains.com/issue/IDEA-246833
https://www.jetbrains.com/help/idea/switching-boot-jdk.html
https://confluence.jetbrains.com/pages/viewpage.action?pageId=173178989
以上方案由官方提供,亲测好用