做一个Spring Boot小例子

2023-11-06

在我的《Spring Boot 框架介绍和使用》里介绍了Spring Boot,但是没有例子。所以这一篇的主要内容就是来做一个小例子。结合我上面那篇一起看效果更佳。

运行项目

创建项目和上篇文章一样,我用了2.0的快照版本的Spring Boot,因为现版本1.5的Thymeleaf还是2.1的版本,比较旧。在Idea中运行Spring Boot项目不如Spring Tool Suite简单,因为在STS中直接保存文件即可触发devtools的重启,而在IDEA中只能手动点击build project命令。

在这里还遇到一点小情况。我原来不明白IDEA中有一个delegate to gradle有什么作用,就胡乱选上了。现在才发现,原来选中这个选项之后,在点击构建项目的时候不会调用IDEA自己的构建工具,而是使用gradle的构建。所以速度会更慢。如果使用IDEA的构建命令,速度会更快一些。

当然这样感觉还是稍微比STS慢一点。所以我又找到了另外一种方法,就是利用gradle的持续构建选项。首先打开一个终端,输入gradle assemble --continuous,这样gradle就会一直编译项目。如果检测到文件发生更改,就会自动重复编译项目,直到我们手动关闭了终端。然后在用gradle bootRun命令正常调试运行项目,当文件发生更改的时候gradle会自动编译项目,从而触发devtools自动重启服务器。

Spring Boot项目在运行的时候支持LiveReload,我们只要在浏览器上安装相应的插件并启用,服务器自动重启之后便会自动刷新浏览器。我们不必每次更改之后手动刷新了。

MVC

多个视图解析器

在Spring Boot中,错误页面可以放在下面的文件夹下。在使用Thymeleaf的时候,情况就变的稍微有点复杂了。

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 404.html
             +- <other templates>

我们希望将重复的模板代码抽出来组合成单独的文件,让其他页面引用。这样以后修改的时候只需要修改一处就可以更改所有页面的效果。但是Thymeleaf默认的代码块导入只能支持同级页面,像下面这样错误页面在单独一个文件夹、公用页面也在单独一个文件夹下的情况,默认的配置不能满足我们的需要。这时候就需要覆盖Spring Boot的自动配置了。

多层试图文件夹

经过一番查阅,我找到了解决办法。这种情况下需要配置的多个视图解析器。在Spring Boot中很简单,我们只需要定义自己的视图解析器,Spring就会自动屏蔽默认配置的。

配置代码如下。我们为代码段单独配置一个视图解析器。然后将这些视图解析器都添加到视图引擎中。这些必须都配置为Spring Bean。如果直接在templateEngine()中new视图解析器并添加,就会抛出ApplicationContext为空的异常。

最后要注意setCheckExistence方法也必须设置。不然的话视图解析器就会认为视图总是存在,所以渲染页面的时候会出现找不到视图文件的情况。所以设置了这个选项,解析器就会先检查文件是否存在,不存在的话就直接返回。这样另一个视图解析器就会寻找视图,最后我们两个文件夹下的视图就可以都找到了。

@Configuration
public class TemplateConfig {
    private boolean cacheable = false;
    private String templatesPrefix = "classpath:templates/";
    private String fragmentsPrefix = "classpath:templates/fragments/";
    private String suffix = ".html";
    private TemplateMode templateMode = TemplateMode.HTML;
    private String encoding = "UTF-8";
    private boolean checkExistence = true;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
        resolver.setPrefix(templatesPrefix);
        resolver.setSuffix(suffix);
        resolver.setCharacterEncoding(encoding);
        resolver.setCacheable(cacheable);
        resolver.setCheckExistence(checkExistence);
        return resolver;
    }

    @Bean
    public SpringResourceTemplateResolver fragmentResolver() {
        SpringResourceTemplateResolver fragmentResolver = new SpringResourceTemplateResolver();
        fragmentResolver.setPrefix(fragmentsPrefix);
        fragmentResolver.setSuffix(suffix);
        fragmentResolver.setCacheable(cacheable);
        fragmentResolver.setTemplateMode(templateMode);
        fragmentResolver.setCharacterEncoding(encoding);
        fragmentResolver.setCheckExistence(checkExistence);
        return fragmentResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.addTemplateResolver(templateResolver());
        templateEngine.addTemplateResolver(fragmentResolver());
        templateEngine.setEnableSpringELCompiler(true);
        templateEngine.addDialect(new Java8TimeDialect());
        return templateEngine;
    }
}

MVC配置

spring自动配置的MVC基本够最基本的使用了,但是在做项目的话肯定要添加自己的配置。我们用Java配置的话也很简单。下面的例子很简单,添加了几个视图控制器,直接将请求和视图连在一起;还定义了两个格式化器。不知道为何Spring没有对这些新日期类的支持,所以我们只能自己写格式化器了。

如果我们只需要向下面添加几个自己的格式化器之类的,向下面这样继承WebMvcConfigurerAdapter即可。如果想完全控制Mvc的设置,可以添加@EnableMvc,这样Spring Boot的自动配置就会完全取消。

在此叨叨两句,如果是旧项目的话就算了。如果使用新项目的话我们在处理日期和时间的时候务必使用Java 8提供的新类,LocalDate、LocalDateTime这些,这些新类符合新标准,提供的新方法也更好用。

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/system-beans").setViewName("beans");
        registry.addViewController("/addUser").setViewName("addUser");
        registry.addViewController("/mvc").setViewName("mvc");
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new LocalDateFormatter());
        registry.addFormatter(new LocalDateTimeFormatter());
    }
}

class LocalDateFormatter implements Formatter<LocalDate> {

    @Override
    public LocalDate parse(String text, Locale locale) throws ParseException {
        return LocalDate.parse(text);
    }

    @Override
    public String print(LocalDate object, Locale locale) {
        return object.toString();
    }
}

class LocalDateTimeFormatter implements Formatter<LocalDateTime> {

    @Override
    public LocalDateTime parse(String text, Locale locale) throws ParseException {
        return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    @Override
    public String print(LocalDateTime object, Locale locale) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return object.format(formatter);

    }
}

Spring Data

多数据源

在开发的时候我们一般有测试数据库和生产数据库,在测试的时候连接到测试数据库,部署的时候改为生产数据库。所以我们这里首先来配置一下多数据源。

application-test.properties中。其实这里什么也不写也可以,Spring 检测到H2 、HSQLDB或Derby的话就会自动创建一个内存嵌入式数据源。

# 数据库设置
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=sa

application-product.properties中,生产数据库为MySQL。

# 数据库设置
spring.datasource.username=root
spring.datasource.password=12345678
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

然后在application.properties中,激活配置即可。以后开发完成之后,改为product即可。

spring.profiles.active=test

使用Hikari连接池

Spring Boot会按照tomcat、HikariCP、DBCP2的顺序查找和使用连接池。不过我看了一下好像HikariCP的性能最好,所以这里我们直接使用HikariCP。

首先需要添加HikariCP的依赖。Spring Boot也包含了对HikariCP的版本号管理,不过它的版本比较低一点,所以我就干脆直接指定了最新的。

compile group: 'com.zaxxer', name: 'HikariCP', version: '2.6.1'

然后添加spring.datasource.type=com.zaxxer.hikari.HikariDataSource即可。

H2 web控制台

如果嵌入式数据库选择了H2,而且项目中添加了spring-boot-devtools。那么Spring还会启用H2的web控制台功能。

如果不需要这个功能可以直接关闭。

spring.h2.console.enabled=false

启用审计

最后我希望使用Spring Data的审计功能来帮我设置用户的注册时间。但是审计不是Spring Boot自动配置的内容。所以我们需要手动开启。

@Configuration
@EnableJpaAuditing
public class JpaConfig {
}

然后在实体类上添加EntityListeners注解。

@Entity
@EntityListeners(AuditingEntityListener.class)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(nullable = false, unique = true)
    private String username;
    @Column(nullable = false)
    private String password;
    @Column
    private String nickname;
    @Column
    private LocalDate birthday;
    @Column
    @CreatedDate
    private LocalDateTime registerTime;
}

这样,当我们处理数据的时候,注册时间就会由Spring自动填充了。

@Transactional
public interface UserRepository extends CrudRepository<User, Integer> {
    Optional<User> findByUsername(String username);
}

Actuator

在项目中添加Actuator的依赖项即可。这样Spring就会自动添加相关的路径映射。

compile("org.springframework.boot:spring-boot-starter-actuator")

为了保证安全,这些都需要验证才能访问。我们可以简单的关闭它,management.security.enabled=false。不过为了安全起见,实际开发中应该设置密码来保护这些敏感信息。

Beans可视化

本来我想将这些端点全做成可视化的,不过看了一些,大部分端点返回来的JSON都比较复杂,是个多层结构,所以最后只做了一个Beans的可视化。推荐一个Chrome插件,json-formatter。安装好之后,在查看这些端点的JSON,就不是糊成一团的了,而是格式化并且语法高亮的形式了。

Beans端点返回的JSON稍微有些奇怪,它是个类似下面这样的对象,也就是个数组,所以获取到数据之后必须使用data[0]这样的语法才能获取里层的对象。

[
  {
    context: "xxx",
    parent: "xxx",
    beans: [
        ...
...

然后页面就可以写成下面这样的。"[[@{/beans}]]"是Thymeleaf的语法,Thymeleaf引擎遇到它会转换为实际的URL。然后jquery获取到对象之后,使用了Knockout将数据绑定到页面上。详细使用方法请参考jQuery和Knockout的官方文档。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="_header::header('系统监控')">
</head>
<body>
<nav th:replace="_navbar::navbar"></nav>
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h2>Beans</h2>
            <h4><a th:href="@{/beans}">点击查看原格式</a></h4>
            <p><strong>context:</strong><span data-bind="text: context"></span></p>
            <p><strong>parent:</strong><span data-bind="text: parent"></span></p>
            <p><strong>数量:</strong>共有<span data-bind="text: beans.length"></span>个Beans</p>
            <table class="table table-bordered table-hover table-responsive table-striped">
                <thead>
                <tr>
                    <th>Beans</th>
                    <th>resource</th>
                    <th>scope</th>
                    <th>type</th>
                </tr>
                </thead>
                <tbody data-bind="foreach: beans">
                <tr>
                    <td data-bind="text: bean"></td>
                    <td data-bind="text: resource"></td>
                    <td data-bind="text: scope"></td>
                    <td data-bind="text: type"></td>
                </tr>
                </tbody>
            </table>
        </div>

    </div>
</div>
<div th:replace="_footer::footer"></div>
<script>
    $(document).ready(function () {
        $.getJSON("[[@{/beans}]]", function (data) {
            ko.applyBindings(data[0])
        })
    })
</script>
</body>
</html>

Hypermedia方式查看数据

如果我们添加 Spring HATEOAS的依赖,也就是下面这个。

compile 'org.springframework.hateoas:spring-hateoas'

然后启用Hypermedia功能。

endpoints.hypermedia.enabled=true

Spring就会在默认/actuator路径下生成一个发现页面,返回所有可用的端点和相应的URL。这个发现页面的URL可以使用endpoints.actuator.path设置,这个发现功能可以使用endpoints.actuator.enabled打开或关闭。

如果还存在HAL Browser的jar包,也就是添加下面的依赖,那么Spring还会开启一个可视化页面覆盖/actuator的JSON形式。可视化页面其实也没啥功能,会把所有的端点和输出以格式化之后的JSON形式输出,如果没安装JSON美化浏览器插件的话这个功能还是挺有用的。

 compile group: 'org.springframework.data', name: 'spring-data-rest-hal-browser', version: '2.6.1.RELEASE'

主页

用Markdown格式化

想了想也没啥写的了。最后就来说说Markdown把。我用的是marked。然后在resouces/statis/md/下建了markdown格式文件。然后页面可以写成类似这样的。同样是通过jQuery获取数据,然后转换为HTML。

<div class="container" id="content">

</div>
<div th:replace="_footer::footer"></div>
<script>
    $(document).ready(function () {
        $.get("[[@{/md/index.md}]]", function (data) {
            $("#content").html(marked(data));
        })
    })
</script>

完整的Spring Boot小例子代码在CSDN代码库上了,有兴趣的同学可以看看。由于项目是Gradle项目,所以可能有些同学不好编译打包。这里我还上传了完整的二进制程序Spring Boot小例子程序,可以直接使用java -jar XXX.jar来运行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

做一个Spring Boot小例子 的相关文章

随机推荐

  • 代码检查工具选型

    源码分析工具选型 1 目前各种主流源码分析工具简单介绍 1 1 checkstyle checkstyle产生于2001年 是以antlr作为java语法分析器的静态源码分析工具 通过checkstyle的xml配置文件可指定源码分析规则
  • 面试篇:虚拟机栈5连问,一听心里就乐了

    面试路上 滴 滴滴 师傅我们到哪了 我还要赶着面试呢 师傅 快了快了 下个路口就到了 真是服了这帮人了 不会开车净往里凑 听着司机师傅的抱怨声 不禁想起首打油诗 满目尾灯红 耳盈刺笛声 心忧迟到久 颓首似雷轰 一下车赶紧小跑就进了富丽堂皇的
  • Android 控件 RecyclerView 看这篇就够了

    Android 控件 RecyclerView 概述 RecyclerView是什么 从Android 5 0开始 谷歌公司推出了一个用于大量数据展示的新控件RecylerView 可以用来代替传统的ListView 更加强大和灵活 Rec
  • 记录生活(一)

    我为什么要写这篇文章呢 主要是想记录自己的生活 我今天刚学css HTML以前学过一点 2022年1月17日 当日下午做的这两个模板 素材文件夹是两个模板共用的的 布局分明 是用百分比 布局的 灰色部分是导航栏 白色部分是用户登录的头像 绿
  • 数据库课后习题

    数据库练习 1 在Course表中添加 教师 列 20个长度的变长字符串 2 为每门课程添加教师信息 3 将教师列修改为非空列 4 查询选修了刘老师的课程的学生 5 检索选修了课程号为C01或C02课程 且成绩高于或等于70分的学生的姓名
  • 如何区分物联网的三大系统

    物联网是基于Internet的各种物理产品信息服务的综合 它主要由三个系统组成 一个是运营支撑系统 即相关应用服务软件 门户 管道 终端等的管理 其二是传感器网络系统 即通过现有的Internet 广电网络 通信网络等实现数据传输和计算 三
  • 最短路经算法简介(Dijkstra算法,A*算法,D*算法)

    转自 http www embhelp com drew algorithm shortpath htm 作者 Drew 据 Drew 所知最短路经算法现在重要的应用有计算机网络路由算法 机器人探路 交通路线导航 人工智能 游戏设计等等 美
  • C# 结构体的使用

    先说一下结构体和类的区别 1 结构体定义的是变量 保存在栈当中 类的对象 实例 保存在堆当中 引用保存在栈当中 结构体是值类型 类是引用类型 2 不能在结构体中定义默认的构造方法 无参 类中可以定义 3 结构体中自定义构造方法后 编译器会提
  • C++基础:for循环

    美好的知识点从出题开始 输出1 100所有的奇数 看到这道题 你可能有点懵 回顾标题 你找到办法了 但你不知道怎么写 来看看for循环的代码框架吧 for 控制变量初始化表达式 条件表达式 增量表达式 语句1 刚看到这 你肯定不太懂 我实际
  • 面试:Tomcat如何优化

    一 增大tomcat运行内存 例如 从默认的 256M增大到2G SET CATALINA OPTS Xms2048m Xmx4096m XX MaxNewSize 512m XX MaxPermSize 256m set JAVA OPT
  • “此帐户并未得到从这个工作站登录的授权”问题

    此帐户并未得到从这个工作站登录的授权 问题 转自 http blog 163 com yumin wang 126 blog static 36293550201210303413140 问题 访问网络共享文件夹时 出错提示为 此帐户并未得
  • [创业-33]:股权、期权、期股的区别

    目录 1 基本概念 1 1 股权 1 2 期权 1 3 期股 二 比较 2 1 享有的权益 2 2 在退出机制 2 3 兑现机制 2 4 分配方式 2 5 获利方式 附录 雷军关于创业公司的股权解读 1 基本概念 1 1 股权 股权 是有限
  • 数据包协议设计(通讯协议的设计)

    一 为什么要设计通讯协议 通常 多设备之间进行通讯多使用数据包的方式 如何从一堆的数据中确定哪些是有效数据 以及这些数据要表达什么意思 为解决这些问题 通常我们需要设计一个通讯协议 依照通讯协议对数据进行解析 就能够正确的找到并使用这些数据
  • 上下文相关音素-状态绑定

    在发音过程中 因为协同发音的影响 同一个音素在不同的位置 其发音变化很大 如下图所示 同样的元音 eh 在不同的单词中的发音在频域上区分非常明显 因为单音素monophone 是上下文独立的 context independent 为了能够
  • RabbitMQ中的限流、return机制、死信队列

    目录 优点 缺点 1 限流 2 return机制 3 死信队列 优点 高可用性 RabbitMQ支持集群和镜像队列等多种方式实现高可用性 保证系统稳定运行 可靠性强 RabbitMQ使用AMQP协议作为消息传递的标准 能够确保消息传递的可靠
  • TypeError: __init__() got an unexpected keyword argument 'categorical_features'

    我的代码 scikit learn 0 22 1 python 3 7 4 错误如下 TypeError init got an unexpected keyword argument categorical features 错误提示的意
  • Visio中插入Mathtype公式

    Visio中插入Mathtype公式 打开visio软件 依次点击 插入 对象 mathtype 6 0 equation 确定 也可以得到我们想要的公式 点击 对象 然后显示出Mathtype公式 点击 Mathtype 7 0 然后显示
  • step7-micro/win 在win10系统下安装步骤

    1 摘要 安装不成功可以多尝试几次 别人安装N次 下载过N个安装包 也就这个安装包安装成功了 其他的不成功 原因尚未可知 2 准备工作 软件包链接 https pan baidu com s 1VcKuwNO3czAi0zSbJiqjDw
  • 关于老赵让改成bootstrap框架搭建的过程

    客户就是上帝 你大爷的 jsp代码 数据与springMvc交互
  • 做一个Spring Boot小例子

    在我的 Spring Boot 框架介绍和使用 里介绍了Spring Boot 但是没有例子 所以这一篇的主要内容就是来做一个小例子 结合我上面那篇一起看效果更佳 运行项目 创建项目和上篇文章一样 我用了2 0的快照版本的Spring Bo