前言 时隔n年终于来到了SSM框架的最后一步SpringBoot,终于要逃离配置地狱了吗,想想都是心动的不得了,也感觉这段时间自己确实好像很求学,不知道自己是咋了。。
什么是微服务架构 微服务架构(通常简称为微服务)是指开发应用所用的一种架构形式。 通过微服务,可将大型应用分解成多个独立的组件,其中每个组件都有各自的责任领域。 在处理一个用户请求时,基于微服务的应用可能会调用许多内部微服务来共同生成其响应。 容器是微服务架构的绝佳示例,因为它们可让您专注于开发服务,而无需担心依赖项。 最初的架构图如下: 最后随着需求变多,用户量变大,数据库公用可能出现冲突矛盾,因此微服务架构诞生:
创建第一个SpringBoot程序 首先你可以再SpringBoot的官网进行创建,当然IDEA也帮你准备了创建方式(本质还是从官网创建),流程如下: 选择Spring Initializr
设置好一些参数后进入下一步,选择SpringBoot DevTools、Spring Web
:
目录结构 这些是为我们开发提前做好一些工作,之后你就创建了你第一个SpringBoot程序了,项目结构图如下: 其中Application文件就是我们SpringBoot的主程序了,之后启动web服务器就是允许这个文件。SpringBoot本质上还是一个Tomcat程序,它内置了tomcat服务器,并且经过了改动,因此启动比Tomcat迅速许多。 结构树状图如下:
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 E:\CTFLEARNING\JAVA\SPRINGBOOT ├─.idea │ └─libraries ├─.mvn │ └─wrapper ├─src │ ├─main │ │ ├─java │ │ │ └─com │ │ │ └─boogipop │ │ │ └─springboot │ │ └─resources │ │ ├─static │ │ └─templates │ └─test │ └─java │ └─com │ └─boogipop │ └─springboot └─target ├─classes │ └─com │ └─boogipop │ └─springboot └─generated-sources └─annotations
创建一个简单的Controller 我们回顾一下SpringMVC,在其中我们需要配置3个xml文件,Spring-Servlet.xml、Mybatis-config.xml、ApplicationContext.xml
,其实还有很多有关Bean的xml文件,面对这一现象我们可以称之为配置地狱 了,而SpringBoot啥配置文件都不需要,唯一需要的就是一个application.properties
,这个后面会讲 所以总结起来SpringBoot真的是一个十分优秀的框架,谁能拒绝呢? 那么我们正式开始创建SpringBoot程序,我们再Application.java
文件的同级目录,创建我们的Controller文件夹,然后在里面写一个Controller: 配置结束后直接启动程序即可:
配置端口 很多人也看到了,我的SpringBoot程序开放端口为7878,正常Tomcat和SpringBoot也都是8080端口,这些属性都可以在application.properties
中配置: 这些配置在之后也会慢慢的接触,先暂时挖个坑拉
SpringBoot自动装配原理 具体请参考上述博客园文章,内容挺复杂的,看看就好
Yaml语法讲解 YAML 是 “YAML Ain’t a Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:”Yet Another Markup Language”(仍是一种标记语言)。 其实yaml的语法看菜鸟教程就懂了,还有就是在学Docker-compose编写yml文件时肯定也懂了,但还是温习一下
语法特点
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要同级元素左对齐即可
#表示注释
数据类型 Yaml一共支持3种类型的元素:
对象:键值对的集合,又称为映射,哈希,字典
数组:一组按次序排列的元素
纯量:实际上就是普通的单一变量
每个数据类型的使用案例如下:
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 Person: name: boogipop age: 18 Dog: name: Kino age: 7 Human: - YourName - YourAge - Nothing Human2: [a ,b ,c ]A: - 1 - 2 - - 1 - 2 - 3 companies: - id: 1 name: company1 price: 200w - id: 2 name: company2 price: 300w languages: - ruby - perl - python websites: Yaml: yaml.org ruby: ruby.org python: python.org boolean: - TRUE - FALSE float: - 3.14 - 1.1415 int: - 1 - 2 null: nodename: 'node' parent: ~ string: - 哈哈 - hello - "hello" data: - 2022-12-12 datatime: - 2022-12-12T15:02:31+08:00
给属性赋值的几种方法 方式一:传统Value赋值 使用Spring的@Value
注解进行赋值,并且配合@Component
注解注册bean,之后直接取出即可
方式二:Yaml配置文件绑定 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 package com.boogipop.springboot.pojo;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;@Component @ConfigurationProperties(prefix = "user") public class User { public User () { } @Override public String toString () { return "User{" + "username='" + username + '\'' + ", address='" + address + '\'' + ", age=" + age + '}' ; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getAddress () { return address; } public void setAddress (String address) { this .address = address; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } private String username; private String address; private int age; }
通过yaml配置文件即可完成属性赋值,就以上述实体类来进行赋值:
1 2 3 4 User: username: Boogipop address: HaiKou-MeiLan age: 19
之后在实体类上通过注解绑定配置文件:prefix="user"
表示将我们的配置文件中User下面的属性赋值给实体类,配置文件的名字由硬性要求,那就是application.yml
目录结构如下: 接下来可以测试一下:
方式三:Properties配置文件绑定 这种方法和yml差不多,都是通过配置文件进行指定
1 2 3 user. nmae=Boogipop address =Haikou age =19
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 package com.boogipop.springboot.pojo;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.PropertySource;import org.springframework.stereotype.Component;@Component @PropertySource("classpath:user.properties") public class User { @Value("${username}") private String username; @Value("${address}") private String address; @Value("${age}") private int age; public User () { } @Override public String toString () { return "User{" + "username='" + username + '\'' + ", address='" + address + '\'' + ", age=" + age + '}' ; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getAddress () { return address; } public void setAddress (String address) { this .address = address;、 } public int getAge () { return age; } public void setAge (int age) { this .age = age; } }
JSR303校验 详情请参考
多环境配置和配置文件位置 SpringBoot中有四个地方可以存放我们的配置文件
项目同级目录
resource目录下(默认)
resource的config目录下
项目同级目录的config目录下
并且可以通过指定spring.profiles.active
来选择环境,多环境配置文件的名称以application-xxx.yml(properties)
来命名,其中xxx表示不同环境,指定环境只需要让spring.profiles.active=xxx
即可
静态资源导入 这里就直接上一下结论了,假如有兴趣分析源码的可以看:
web项目中resource目录下
项目中的resource/resource目录下
项目中的resource/static目录下
项目中的resource/public目录下
优先级resource>static>public
其实还有一个webjars的路径webjars/jquery/3.5.1/jquery.js
,太鸡肋了
SpringBoot首页设置 你可以直接把index.html放在templates目录或者static文件夹下,static没有就回去templates找,更多方法请看:https://www.hangge.com/blog/cache/detail_2528.html
Thymeleaf模板引擎 一个是依赖:
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-thymeleaf</artifactId > </dependency >
另外一个就是语法问题了: Sir this way↓
Configuration配置 我们可以在一个类上加上@configuration
注解,来代表一个配置类,配置类可以配置拦截器,等等: 并且我们需要实现WebMvcConfigurer
接口 从上图中可以看到可重写方法,里面有很多,比如addviewcontroller就可以手动加一个controller
员工管理系统 | 搭建 我也不知道狂神犯什么病,他居然不用mybatis,就直接写个map模拟数据,逆天,那有啥办法,先跟着来一遍然后后面换掉 POJO:
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 package com.boogipop.springboot.pojo;import java.util.Date;public class Employee { private Integer id; private String name; private String email; private Integer gender; private Department department; public Employee (Integer id, String name, String email, Integer gender, Department department, Date birth) { this .id = id; this .name = name; this .email = email; this .gender = gender; this .department = department; this .birth = birth; } public Employee () { } @Override public String toString () { return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", email='" + email + '\'' + ", gender=" + gender + ", department=" + department + ", birth=" + birth + '}' ; } public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public String getEmail () { return email; } public void setEmail (String email) { this .email = email; } public Integer getGender () { return gender; } public void setGender (Integer gender) { this .gender = gender; } public Department getDepartment () { return department; } public void setDepartment (Department department) { this .department = department; } public Date getBirth () { return birth; } public void setBirth (Date birth) { this .birth = birth; } private Date birth; }
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 package com.boogipop.springboot.pojo;public class Department { private Integer id; private String departmentName; public Department () { } public Department (Integer id, String departmentName) { this .id = id; this .departmentName = departmentName; } @Override public String toString () { return "Department{" + "id=" + id + ", departmentName='" + departmentName + '\'' + '}' ; } public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getDepartmentName () { return departmentName; } public void setDepartmentName (String departmentName) { this .departmentName = departmentName; } }
Mapper:
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 package com.boogipop.springboot.mapper;import com.boogipop.springboot.pojo.Department;import java.util.Collection;import java.util.HashMap;import java.util.Map;public class DepartmentMapper { private static int initid=5 ; private static Map<String,Department> departments=null ; static { departments=new HashMap <>(); departments.put("1" ,new Department (1 ,"斧乃木" )); departments.put("2" ,new Department (2 ,"八九寺真宵" )); departments.put("3" ,new Department (3 ,"阿良良木历" )); departments.put("4" ,new Department (4 ,"不吉波普不笑" )); } public void adddepartment (Department department) { if (department.getId()==null ){ department.setId(initid++); } departments.put(String.valueOf(department.getId()),department); } public Collection<Department> getalldepartment () { return departments.values(); } public void deletedepartment (String id) { departments.remove(id); } }
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 package com.boogipop.springboot.mapper;import com.boogipop.springboot.pojo.Department;import com.boogipop.springboot.pojo.Employee;import java.util.Collection;import java.util.Date;import java.util.HashMap;import java.util.Map;public class EmployeeMapper { private static Map<String, Employee> employees=null ; private static Integer initid=5 ; static { employees=new HashMap <>(); employees.put("1" ,new Employee (1 ,"Boh1" ,"[email protected] " ,1 ,new Department (1 ,"斧乃木" ),new Date ())); employees.put("2" ,new Employee (2 ,"Boh2" ,"[email protected] " ,1 ,new Department (1 ,"斧乃木" ),new Date ())); employees.put("3" ,new Employee (3 ,"Boh3" ,"[email protected] " ,1 ,new Department (1 ,"斧乃木" ),new Date ())); employees.put("4" ,new Employee (4 ,"Boh4" ,"[email protected] " ,1 ,new Department (1 ,"斧乃木" ),new Date ())); } public void addemployee (Employee employee) { if (employee.getId()==null ){ employee.setId(initid++); } employees.put(String.valueOf(employee.getId()),employee); } public Collection<Employee> getallemployees () { return employees.values(); } public void delete (String id) { employees.remove(id); } }
搭建好了这两个之后就是准备静态资源了,目录结构如下:
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 <!doctype html > <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <head > <meta charset ="utf-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1, shrink-to-fit=no" > <meta name ="description" content ="" > <meta name ="author" content ="" > <link rel ="icon" href ="favicon.ico" > <title > Dashboard Template for Bootstrap</title > <link th:href ="@{../static/css/bootstrap.min.css}" rel ="stylesheet" > <link th:href ="@{../static/css/dashboard.css}" rel ="stylesheet" > </head > <body > <nav class ="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" > <a class ="navbar-brand col-sm-3 col-md-2 mr-0" href ="#" > Company name</a > <input class ="form-control form-control-dark w-100" type ="text" placeholder ="Search" aria-label ="Search" > <ul class ="navbar-nav px-3" > <li class ="nav-item text-nowrap" > <a class ="nav-link" href ="#" > Sign out</a > </li > </ul > </nav > <div class ="container-fluid" > <div class ="row" > <nav class ="col-md-2 d-none d-md-block bg-light sidebar" > <div class ="sidebar-sticky" > <ul class ="nav flex-column" > <li class ="nav-item" > <a class ="nav-link active" href ="#" > <span data-feather ="home" > </span > Dashboard <span class ="sr-only" > (current)</span > </a > </li > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="file" > </span > Orders </a > </li > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="shopping-cart" > </span > Products </a > </li > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="users" > </span > Customers </a > </li > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="bar-chart-2" > </span > Reports </a > </li > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="layers" > </span > Integrations </a > </li > </ul > <h6 class ="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted" > <span > Saved reports</span > <a class ="d-flex align-items-center text-muted" href ="#" > <span data-feather ="plus-circle" > </span > </a > </h6 > <ul class ="nav flex-column mb-2" > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="file-text" > </span > Current month </a > </li > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="file-text" > </span > Last quarter </a > </li > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="file-text" > </span > Social engagement </a > </li > <li class ="nav-item" > <a class ="nav-link" href ="#" > <span data-feather ="file-text" > </span > Year-end sale </a > </li > </ul > </div > </nav > <main role ="main" class ="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" > <div class ="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom" > <h1 class ="h2" > Dashboard</h1 > <div class ="btn-toolbar mb-2 mb-md-0" > <div class ="btn-group mr-2" > <button class ="btn btn-sm btn-outline-secondary" > Share</button > <button class ="btn btn-sm btn-outline-secondary" > Export</button > </div > <button class ="btn btn-sm btn-outline-secondary dropdown-toggle" > <span data-feather ="calendar" > </span > This week </button > </div > </div > <canvas class ="my-4" id ="myChart" width ="900" height ="380" > </canvas > <h2 > Section title</h2 > <div class ="table-responsive" > <table class ="table table-striped table-sm" > <thead > <tr > <th > #</th > <th > Header</th > <th > Header</th > <th > Header</th > <th > Header</th > </tr > </thead > <tbody > <tr > <td > 1,001</td > <td > Lorem</td > <td > ipsum</td > <td > dolor</td > <td > sit</td > </tr > <tr > <td > 1,002</td > <td > amet</td > <td > consectetur</td > <td > adipiscing</td > <td > elit</td > </tr > <tr > <td > 1,003</td > <td > Integer</td > <td > nec</td > <td > odio</td > <td > Praesent</td > </tr > <tr > <td > 1,003</td > <td > libero</td > <td > Sed</td > <td > cursus</td > <td > ante</td > </tr > <tr > <td > 1,004</td > <td > dapibus</td > <td > diam</td > <td > Sed</td > <td > nisi</td > </tr > <tr > <td > 1,005</td > <td > Nulla</td > <td > quis</td > <td > sem</td > <td > at</td > </tr > <tr > <td > 1,006</td > <td > nibh</td > <td > elementum</td > <td > imperdiet</td > <td > Duis</td > </tr > <tr > <td > 1,007</td > <td > sagittis</td > <td > ipsum</td > <td > Praesent</td > <td > mauris</td > </tr > <tr > <td > 1,008</td > <td > Fusce</td > <td > nec</td > <td > tellus</td > <td > sed</td > </tr > <tr > <td > 1,009</td > <td > augue</td > <td > semper</td > <td > porta</td > <td > Mauris</td > </tr > <tr > <td > 1,010</td > <td > massa</td > <td > Vestibulum</td > <td > lacinia</td > <td > arcu</td > </tr > <tr > <td > 1,011</td > <td > eget</td > <td > nulla</td > <td > Class</td > <td > aptent</td > </tr > <tr > <td > 1,012</td > <td > taciti</td > <td > sociosqu</td > <td > ad</td > <td > litora</td > </tr > <tr > <td > 1,013</td > <td > torquent</td > <td > per</td > <td > conubia</td > <td > nostra</td > </tr > <tr > <td > 1,014</td > <td > per</td > <td > inceptos</td > <td > himenaeos</td > <td > Curabitur</td > </tr > <tr > <td > 1,015</td > <td > sodales</td > <td > ligula</td > <td > in</td > <td > libero</td > </tr > </tbody > </table > </div > </main > </div > </div > <script src ="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity ="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin ="anonymous" > </script > <script > window .jQuery || document .write ('<script th:src="@{../static/js/jquery-slim.min.js}"><\/script>' )</script > <script th:src ="@{../static/js/popper.min.js}" > </script > <script th:src ="@{../static/js/bootstrap.min.js}" > </script > <script src ="https://unpkg.com/feather-icons/dist/feather.min.js" > </script > <script > feather.replace() </script > <script src ="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js" > </script > <script > var ctx = document .getElementById ("myChart" ); var myChart = new Chart (ctx, { type : 'line' , data : { labels : ["Sunday" , "Monday" , "Tuesday" , "Wednesday" , "Thursday" , "Friday" , "Saturday" ], datasets : [{ data : [15339 , 21345 , 18483 , 24003 , 23489 , 24092 , 12034 ], lineTension : 0 , backgroundColor : 'transparent' , borderColor : '#007bff' , borderWidth : 4 , pointBackgroundColor : '#007bff' }] }, options : { scales : { yAxes : [{ ticks : { beginAtZero : false } }] }, legend : { display : false , } } }); </script > </body > </html >
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 <!doctype html > <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <head > <meta charset ="utf-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1, shrink-to-fit=no" > <meta name ="description" content ="" > <meta name ="author" content ="" > <link rel ="icon" href ="favicon.ico" > <title > Signin Template for Bootstrap</title > <link th:href ="@{../static/css/bootstrap.min.css}" rel ="stylesheet" > <link th:href ="@{../static/css/signin.css}" rel ="stylesheet" > </head > <body class ="text-center" > <form class ="form-signin" > <img class ="mb-4" src ="https://getbootstrap.com/docs/5.3/assets/brand/bootstrap-logo.svg" alt ="" width ="72" height ="72" > <h1 class ="h3 mb-3 font-weight-normal" > Please sign in</h1 > <label for ="inputEmail" class ="sr-only" > Email address</label > <input type ="email" id ="inputEmail" class ="form-control" placeholder ="Email address" required autofocus > <label for ="inputPassword" class ="sr-only" > Password</label > <input type ="password" id ="inputPassword" class ="form-control" placeholder ="Password" required > <div class ="checkbox mb-3" > <label > <input type ="checkbox" value ="remember-me" > Remember me </label > </div > <button class ="btn btn-lg btn-primary btn-block" type ="submit" > Sign in</button > <p class ="mt-5 mb-3 text-muted" > © 2017-2018</p > </form > </body > </html >
上述的@{}
为thymeleaf的模板语法,和jsp中的page.context.getcontextpath是一个意思,指向项目根目录
然后自定义一下首页:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.boogipop.springboot.config;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration public class DIYconfig implements WebMvcConfigurer { @Override public void addViewControllers (ViewControllerRegistry registry) { registry.addViewController("/" ).setViewName("index" ); registry.addViewController("/index" ).setViewName("index" ); registry.addViewController("/index.html" ).setViewName("index" ); } }
上面说到的只需要继承WebMvcConfigurer然后加上注解即可自定义配置
员工管理系统 | 国际化 国际化也就是中文翻译,支持不同语言的网站