GeXiangDong

精通Java、SQL、Spring的拼写,擅长Linux、Windows的开关机

0%

本文不是为了比较双方优劣,是因为我经常在两类项目中切换,有时搞混,列出来方便自己记忆和速查。

对比项目 微信小程序 VUE.js
模版内显示变量
模版中元素属性使用变量 view class=”“ div :class=”var”
元素事件捕获 bindtap=”userClicked” @click=”userClicked”
给事件处理函数传递变量 在元素上写 data-varname=”“, js中用 event.target.dataset.varname获取 @click=”userClicked(var1, var2)”,直接写在方法名后,和调用相同
事件处理函数中获取event 方法可接收的唯一参数就是event @click=”userClicked($event)” 在模版中写上特殊变量 $event
阻止事件向父级元素传递 bindXxx改为catchXXX,例如:catchtap=”userclicked” 用.stop 例如: @click.stop=”userClicked” 或者@clicked.stop表明不处理直接阻止
模版内调用JS方法 只能调用wxs内声明的方法 可以直接调用vue内method段声明的方法
页面生命周期事件 onLoad created
onShow mounted
script部分方法 直接写在Page内和onload同级 写在methods部分下,methods和created同级
script部分对data的访问 this.data.xxx this.xxx
component中对props内属性访问 this.properties.xxx this.xxx
data 部分 可在程序中随时增加 先在data中声明,不声明的,动态增加 模版部分也不能使用
模版引用data遇到null 无显示或显示NULL 异常出错
模版内循环 wx:for=”array” wx:key=”index” wx:item=”item” v-for=”(item, index) in array” :key=”index”
模版内虚拟元素 block template 在v-for上应用时,需要把:key 应用与所有一级子元素并保持key唯一
自定义组件 created 方法不能调用 setData,(可用attached事件替代部分) created 方法可以使用this ,能改变data内数据

git用起来很方便,小型团队不需要权限区分时,仅仅使用git就够了。

需要权限区分时,可以使用gitolite来做权限控制。

安装

首先安装好 git openssh 等,这里不再累述。

ssh到安装好git的服务器上,

切换到git用户 sudo su - git ,之后确认下 .ssh 目录下没有 authorization_keys 文件或改文件为空。(以下这些命令都在git用户下执行)

运行下面的命令

1
2
3
git clone https://github.com/sitaramc/gitolite
mkdir -p $HOME/bin
gitolite/install -to $HOME/bin

这三个命令的作用是,从github.com克隆gitolite的安装仓库,在当前用户(git)的用户目录下创建一个bin目录,并且把gitolite安装到这个目录。

安装到这个目录后,由于path里没有这个目录,调用此目录下新安装的命令时,需要写全路径,不过这影响不大,因为这几个命令不会经常用。

下面这个很关键,不要错,把自己用的客户机上的公钥(.ssh目录下的id_rsa.pub)文件拷贝到服务器上git用户目录下,并且命名为admin.pub,之后再运行下面的命令

1
/home/git/bin/gitolite setup -pk admin.pub

此命令运行成功后,会出现如下内容:

1
2
Initialized empty Git repository in /home/git/repositories/gitolite-admin.git/
Initialized empty Git repository in /home/git/repositories/testing.git/

而且会在git用户目录下创建 repository目录和projects.list文件。
如果用的公钥不正确,可以删除这2个目录/文件,然后重新来过。

此时gitolite已经安装好了,要设置仓库、用户和权限,都需要在客户端(就是前面生成admin.pub的机器)上进行了

日常管理

首先把gitolite-admin这个仓库克隆到本地,所有管理工作都由这个仓库进行。

1
git clone ssh://git@host/gitolite-admin

如果出错,请首先检查客户端电脑的用户公钥是否就是安装过程中使用的admin.pub。

克隆下 gitolite-admin 这个仓库后,会发现有2个目录 conf 和 keydir,

  • conf是仓库和用户的配置目录,内有一个gitolite.conf 文件,存储用户和仓库的对应权限
  • keydir 是保存的用户的公钥,按照上述安装步骤进行的,应该已经有一个 admin.pub 文件了

创建仓库

不需要手工创建仓库,在 conf/gitolite.conf 文件中配置的仓库名,在commit并push后,会自动被创建。

仓库的URL

仓库的URL是

ssh://git@host/repo-name

例如:

ssh://git@192.168.1.2/testing

仓库名后面有或没有.git都可以。

gitolite 命令

除了安装时使用gitolite命令的setup参数初始化了 gitolite-admin 和 testing 两个仓库外,这个命令还可以接收以下这些参数

list-groups                 list all group names in conf
list-users                  list all users/user groups in conf
list-repos                  list all repos/repo groups in conf
list-phy-repos              list all repos actually on disk
list-memberships            list all groups a name is a member of
list-members                list all members of a group

这可以帮助我们确认服务器上到底有哪些仓库/用户等。

参考

gitolite github网址:https://github.com/sitaramc/gitolite

安装 babel-plugin-transform-remove-consol

1
npm install babel-plugin-transform-remove-console --save-dev

修改 babel.config.js 文件,加入 plugin transform-remove-console

1
2
3
module.exports = {
plugins: ["transform-remove-console"]
};

这是再运行项目就不会有console输出了,但是我们期望的是 development 环境有,production 环境没有,可以这样设置:

1
2
3
4
5
6
7
8
9
10
var babelconfig = {
presets: ["@vue/cli-plugin-babel/preset"], //其它原有设置
plugins: []
};
if (process.env.NODE_ENV === "production") {
// production 环境则增加此插件
babelconfig.plugins.push("transform-remove-console");
}

module.exports = babelconfig;

这样就可以了。

异常 I

spring cloud 的 eureka server 启动时出现如下错误

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
09:17:44.673 [SpringContextShutdownHook] WARN  c.n.d.s.t.d.RetryableEurekaHttpClient - Request execution failed with message: java.net.ConnectException: Connection refused (Connection refused)
09:17:44.674 [SpringContextShutdownHook] ERROR c.netflix.discovery.DiscoveryClient - DiscoveryClient_REGISTER-SERVER/192.168.123.121:register-server:8012 - de-registration failedCannot execute request on any known server
com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
at com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:112)
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.cancel(EurekaHttpClientDecorator.java:71)
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$2.execute(EurekaHttpClientDecorator.java:74)
at com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77)
at com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.cancel(EurekaHttpClientDecorator.java:71)
at com.netflix.discovery.DiscoveryClient.unregister(DiscoveryClient.java:941)
at com.netflix.discovery.DiscoveryClient.shutdown(DiscoveryClient.java:919)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeDestroyMethods(InitDestroyAnnotationBeanPostProcessor.java:347)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeDestruction(InitDestroyAnnotationBeanPostProcessor.java:177)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:242)
at org.springframework.beans.factory.support.DisposableBeanAdapter.run(DisposableBeanAdapter.java:235)
at org.springframework.cloud.context.scope.GenericScope$BeanLifecycleWrapper.destroy(GenericScope.java:403)
at org.springframework.cloud.context.scope.GenericScope.destroy(GenericScope.java:142)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:258)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:571)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:543)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1072)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:504)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1065)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1060)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1029)
at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:948)

这个错误是由于 Eureka 启动时默认会把自己注册到注册中心(默认注册中心是localhost,虽然没配置,但是有这么个默认值),而此时没有注册中心(自己是注册中心,尚未启动),所以出错了。

解决方案很简单,禁止注册就好了

1
2
3
4
5
6
eureka:
instance:
preferIpAddress: true
client:
register-with-eureka: false
fetch-registry: false

如果网络上已经有注册中心,也可以提供注册中心的URL,让 eureka server 能购找到注册中心也可

1
2
3
4
5
6
eureka:
client:
register-with-eureka: true
fetch-registry: false
service-url:
defaultZone: http://192.168.1.1/eureka/

异常 II

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
09:42:18.813 [TaskBatchingWorker-target_localhost-9] ERROR c.n.e.c.ReplicationTaskProcessor - Network level connection to peer localhost; retrying after delay
com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused (Connection refused)
at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187)
at com.netflix.eureka.cluster.DynamicGZIPContentEncodingFilter.handle(DynamicGZIPContentEncodingFilter.java:48)
at com.netflix.discovery.EurekaIdentityHeaderFilter.handle(EurekaIdentityHeaderFilter.java:27)
at com.sun.jersey.api.client.Client.handle(Client.java:652)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682)
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:570)
at com.netflix.eureka.transport.JerseyReplicationClient.submitBatchUpdates(JerseyReplicationClient.java:117)
at com.netflix.eureka.cluster.ReplicationTaskProcessor.process(ReplicationTaskProcessor.java:80)
at com.netflix.eureka.util.batcher.TaskExecutors$BatchWorkerRunnable.run(TaskExecutors.java:193)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
at java.base/java.net.Socket.connect(Socket.java:591)
at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:121)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:605)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:440)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:118)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:173)
... 10 common frames omitted

erureka server 使用中出现上面的错误,这也是2个注册中心连接复制信息造成的。如果只有一个注册中心,可以用这个禁止:

1
2
3
eureka:
server:
maxThreadsForPeerReplication: 0

原因

在微服务体系中,注册中心是十分重要的一环,注册中心如果死掉,那么所有微服务之间的通讯就没法进行了,整个系统陷入瘫痪。所以eureka才默认就开启了双机模式,这也是开发环境中出现上述2个异常的原因,没有使用双注册中心的备份机制。

生产环境应该使用双注册中心(或更多),不要开启上述几个设置仅仅屏蔽异常。

Spring Security 5.x 开始把密码机制升级了,使用DelegatingPasswordEncoder。 这是一种支持多种加密密码并存的方法,取代了以前只支持一种密码机制的方法。

这种升级需要密码的密文增加一个前缀,来说明密文是通过那种办法加密的,例如之前用 BCryptPasswordEncoder 加密出来的密文

$2a$10$H2z/oHZgviqC8srzsCZq/ObzTNRTfygC4N0NEZlm5trYPFrvdNHeS

需要被存储为:

{bcrypt}$2a$10$H2z/oHZgviqC8srzsCZq/ObzTNRTfygC4N0NEZlm5trYPFrvdNHeS

如果是从 spring security 4.x 升级过了,需要修改下数据库里保存的密文密码。

在开发测试过程中可以使用 {noop}12345 这样的明文密码就比较方便了。

可能遇到的异常或警告

下面2种异常/警告 都是和密码加密有关的。

WARN o.s.s.c.bcrypt.BCryptPasswordEncoder - Encoded password does not look like BCrypt

这个警告是因为密文前缺少{bcypt},用了BCryptPasswordEncoder去match,Spring 会给出这个警告。

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id “null”

这也是因为密文没有指明加密方式的前缀,用了DelegatingPasswordEncoder去match这个password是否正确,密文的加密方法前缀是null,才出这个错。

其它

另外需要注意的,除了WebSecurityConfigurerAdapter会涉及到登录用户的密码外,在oauth Authentication Server的 ClientDetail 里的 client_secret 也需要类似处理。

参考

https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-encoding

在使用jason做json和类的转换时,遇到错误

Cause: java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.LinkedHashMap<java.lang.Object,java.lang.Object>` out of START_ARRAY token

是因为json是数组格式,而提供的待转化成的类是 Map 格式,导致转化失败。

问题表现

在老程序升级到java9或以后版本时,如果遇到 java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException 错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:645) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:475) ~[spring-beans-5.2.1.RELEASE.jar:5.2.1.RELEASE]

原因

这是由于JAXB API没找到造成的。 JAXB 在是 Java EE API的一部分,在java9开始不再包含在默认的java9的module中(java9开始分module了),甚至在java11开始,干脆把它给移除出JDK了。

解决方法

知道了原因解决办法也就有了:

  • 继续用Java8
  • 命令后增加 add-modules java.xml.bin,这个方法只对 java9 java10有效
  • 一劳永逸的解决问题(对9和以后版本都生效)增加maven依赖(或者gradle)
1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>

<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>

其它

这篇文章:org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat也遇到过相同的JAXBException,解决方式类似。

用java的 Graphics 的 drawString 往图片上描画文字的时候,文字边缘可能会出现粗糙的锯齿(如下图,上部的”文“字的放大效果),可以通过Graphics2D设置抗锯齿效果。

代码和两种的比较效果如下(只有第18行是设置抗锯齿效果的代码):

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
BufferedImage img = new BufferedImage(800, 300, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();

InputStream fi = Thread.currentThread().getContextClassLoader().getResourceAsStream("fonts/msyh.ttf");
BufferedInputStream bisYh = new BufferedInputStream(fi);
Font yahei = Font.createFont(Font.TRUETYPE_FONT, bisYh);

g.setColor(Color.WHITE);
g.fillRect(0, 0, 800, 300);

Font font = yahei.deriveFont(Font.BOLD, 48);
g.setColor(Color.BLACK);

g.setFont(font);
g.drawString("中文字体,无抗锯齿效果", 10, 50);

// 下面这行是设置文字抗锯齿效果的
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.drawString("中文字体,有抗锯齿效果", 10, 150);

FileOutputStream fos = new FileOutputStream("target/font.png" );
ImageIO.write(img, "png", fos);

fos.flush();
fos.close();

字体

通过上图可以看出,设置抗锯齿效果后,会在文字边缘有些过度颜色的点。如果是要在单色打印机上打印(例如android下连接小票打印机),就不需要这种抗锯齿效果了,有它反而会增加麻烦,我就是在调试android下单色打印机时发现的这个效果。

描画图片时也可以设置抗锯齿效果

1
2
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

JDK中Graphics2D类 drawString(String str, float x, float y) 方法的后两个参数是用来控制字符串的位置。

这2个参数即不是字符串左上角距画布原点的坐标,也不是左下角距原点的坐标,而是baseline起点距原点的坐标。说到baseline,请参照下图

字体

如上图,红色线是字体描画时的baseline(基线),小写英文字母是可能有些部分在baseline以下的,比如 gjpqy 等,中文每个字都有可能有部分在baseline以下。baseline和字的最上方之间的距离称作 ascent,baseline和最下方之间的距离叫 descent. 这两段距离可以通过 FontMetrics 类获取。

如果要想被画的文字左上角在x,y 位置,可以通过如下代码

1
2
3
4
5
public void drawString(Graphics2D g, String s, float x, float y){
FontMetrics metrics = g.getFontMetrics(g.getFont());
g.drawString(s, x, y - metrics.getAscent());
}

通过FontMetrics类,我们还可以获取一段文字的实际占用宽度等,可以实现右对齐和居中对齐

spring boot 项目访问某个controller时出错,错误信息如下:

2019-10-19 09:46:01.451 ERROR 1040 --- [nio-4675-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Circular view path []: would dispatch back to the current handler URL [/] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)] with root cause

javax.servlet.ServletException: Circular view path []: would dispatch back to the current handler URL [/] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
    at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:209) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:147) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1370) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1116) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.14.jar:9.0.14]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]

这个错误是由于访问的是 Controller, 而该 Controller对方的方法没有对应的视图造成的。 我这里出现这个错误,是因为我本来就不需要视图,我是想返回 JSON,但把 RestController 误写成了 Controller。