Dashboard
Section title
id | name | class | favourite | Header |
---|---|---|---|---|
1,001 | Lorem | ipsum | dolor | sit |
目录
一、Springboot简介
二、分析SpringBoot源码
三、YAML
四、自动装配再理解
五、WEB开发
六、Thymeleaf模版引擎
七、WebMVC自动配置原理
八、MVC的员工管理系统
Gitee地址:狂神-SpringBoot: 学习狂神的课程时,写的练习项目 - Gitee.com
Spring是一个开源框架,2003 年兴起的一个轻量级的Java 开发框架,SpringBoot是对他的加强
Spring Boot的主要优点:
开发环境
Spring官方提供了非常方便的工具让我们快速构建应用
构建方式一:Spring Initializr:https://start.spring.io/
填写项目信息
构建方式二:打开https://start.spring.io/网站,构建maven项目
点击Generate,会下载构建好的项目工程
解压缩打开,自动下载jar包
好了,项目这时就可以启动了!
项目结构分析:
1、程序的主启动类Application.java
2、一个 application.properties 配置文件
3、一个 测试类
4、一个 pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.13.RELEASE
com.kuang
HelloWorld
0.0.1-SNAPSHOT
HelloWorld
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
编写一个HelloController后,运行主启动类
访问8080端口
简单几步,就完成了一个web接口的开发,SpringBoot就是这么简单。
所以我们常用它来建立我们的微服务项目!
简单的3步,就可以打包项目
org.apache.maven.plugins
maven-resources-plugin
3.1.0
org.apache.maven.plugins
maven-surefire-plugin
true
图案可以到:https://www.bootschool.net/ascii 这个网站生成,然后拷贝到文件中即可!
父工程师官网默认设置好了的资源和依赖,已有的,我们配置时就不用写版本号
org.springframework.boot
spring-boot-starter-parent
2.2.13.RELEASE
点spring-boot-starter-parent进去看父工程,就会看到官方配置好的依赖和资源版本号
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;
org.springframework.boot
spring-boot-starter-web
//@SpringBootApplication : 标注这个类是一个Springboot的应用
@SpringBootApplication
public class Springboot01HellowordApplication {
//将Springboot的应用启动
public static void main(String[] args) {
SpringApplication.run(Springboot01HellowordApplication.class, args);
}
}
① 分析SpringBootApplication源码
点击注解进入源码,开始一层层的分析
// 主启动类的注解,一个tab表示点进去一次
@SpringBootApplication
@SpringBootConfiguration// 表明是一个SpringBoot配置文件
@Configuration// 再次说明这是一个Spring配置
@EnableAutoConfiguration // 自动配置
@AutoConfigurationPackage
@Import(AutoConfigurationPackages.Registrar.class)
@Import(AutoConfigurationImportSelector.class)
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
@EnableAutoConfiguration
getCandidateConfigurations
方法
getCandidateConfigurations
方法:获得候选的配置protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
SpringFactoriesLoader.loadFactoryNames
,点进去,找到loadSpringFactories
方法
SpringFactoriesLoader
类中的预定义的自动装配路径 FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List loadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
//获得classLoader
MultiValueMap result = cache.get(classLoader);
if (result != null) {
return result;
}
...
}
大功告成!
@ComponentScan
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
② 自动装配
EnableConfigrutionProperties(xxx.class)
:表明这是一个自动配置类,加载某些配置XXXProperties.class
:封装配置文件中的属性,yam中需要填入= 它指定的前缀+方法③ 工作原理总结
④ run方法
我最初以为就是运行了一个main方法,没想到却开启了一个服务;
//@SpringBootApplication : 标注这个类是一个springboot的应用,启动类下的所有资源被导入
@SpringBootApplication
public class Springboot01HelloworldApplication {
public static void main(String[] args) {
//将springboot应用启动
//SpringAplication类
//run 方法
SpringApplication.run(Springboot01HelloworldApplication.class, args);
}
}
分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;
SpringApplication这个类主要做了以下四件事情:
SpringBoot中的配置文件详解(yml、properties全局配置和自定义配置)
SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的
application.properties
语法结构 :key=value
application.yml
语法结构 :key:空格 value
自定义配置在第7章
其让人最容易上手的特色是巧妙避开各种封闭符号,如:引号、各种括号等,这些符号在嵌套结构时会变得复杂而难以辨认
传统xml配置:
8081
yaml配置:
server:
prot: 8080
说明:语法要求严格!
字面值:普通字符换、数值、布尔类型,直接写成k:v,字符串默认不用加‘’或“”
注意:
比如 :name: “kuang \n shen” 输出 :kuang 换行 shen
比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen
对象、Map:属性值必须和Bean中的对应一致
Student:
name: zhangsan
age: nan
#行内写法
student: {name: qinjiang,age: 3}
数组:使用 - 表示一个元素
Countries:
- Chine
- USA
#行内写法
pets: [cat,dog,pig]
yaml文件更强大的地方在于,他可以给我们的实体类直接注入匹配值!
原本给bean注入属性值的方法
编写一个实体类User,添加@Component,再在字段上加@Value赋值
@Data
@Component
public class User {
@Value("小狂狂")
private String name;
private int age;
}
在测试类引入User,编写测试方法
@SpringBootTest
class HelloWorldApplicationTests {
@Autowired
User user;
@Test
void value() {
System.out.println(user.toString());
}
}
启动项目测试,打印User的值
通过配置文件给bean注入属性的方法
导入依赖
org.springframework.boot
spring-boot-configuration-processor
true
添加注解,@ConfigurationProperties(prefix = “person”)默认是从全局配置获取,文件名只能是application.yml
@Data
@Component
@ConfigurationProperties(prefix = "person")
public class User {
@Value("小狂狂")
private String name;
private int age;
}
application.yml
#对象
person:
name: wang
age: 3
启动项目测试,打印User的值
我们去在resources目录下新建一个person.properties文件
name=person1
age=5
然后在我们的代码中指定加载person.properties文件
@Data
@Component
//@ConfigurationProperties(prefix = "person")
@PropertySource(value = "classpath:person.properties")
public class User {
// SPEL表达式取出配置文件内的值
@Value("${name}")
private String name;
@Value("${age}")
private int age;
}
再次输出测试一下:指定配置文件绑定成功!
修改上面的person.properties文件内容
# 配置文件占位符:随机uuid
name=person1${random.uuid}
age=5
启动项目测试
1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加
2、松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下
3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性
4、复杂类型封装,yml中可以封装对象 , 使用value就不支持
结论:
就是一种数据校验格式,在类上绑定@Validated
,在属性上使用指定的参数如@Email(message="邮箱格式错误")
我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;
例如:
但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件;
我们需要通过一个配置来选择需要激活的环境:
#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:
在本地配置4个不同位置的application.yml,启动项目测试
来分割多个yml配置,并且用profiles来命名
一个yml文件可以使用active来区分配置,比properties强大之一
server:
port: 8081
#选择要激活那个环境块
spring:
profiles:
active: prod
---
server:
port: 8083
spring:
profiles: dev #配置环境的名称
---
server:
port: 8084
spring:
profiles: prod #配置环境的名称
我们以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;
//表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件;
@Configuration
//启动指定类的ConfigurationProperties功能;
//进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来;
//并把HttpProperties加入到ioc容器中
@EnableConfigurationProperties({HttpProperties.class})
//Spring底层@Conditional注解
// 根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
//这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(type = Type.SERVLET)
//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass({CharacterEncodingFilter.class})
//判断配置文件中是否存在某个配置:spring.http.encoding.enabled;
//如果不存在,判断也是成立的
//即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = {"enabled"}, matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
//他已经和SpringBoot的配置文件映射了
private final Encoding properties;
//只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
//给容器中添加一个组件,这个组件的某些值需要从properties中获取
@Bean
//判断容器没有这个组件?
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
}
一句话总结 :根据当前不同的条件判断,决定这个配置类是否生效!
1、SpringBoot启动会加载大量的自动配置类
2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
xxxxAutoConfigurartion:自动配置类;给容器中添加组件
xxxxProperties:封装配置文件中相关属性;
了解完自动装配的原理后,我们来关注一个细节问题,自动配置类必须在一定的条件下才能生效
它是Spring原生的@Conditional的派生注解
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;
我们怎么知道哪些自动配置类生效?
我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
debug: true
Positive matches:(自动配置类启用的:正匹配)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Unconditional classes: (没有条件的类)
Webjars本质就是以jar包的方式引入我们的静态资源 , 我们以前要导入一个静态资源文件,直接导入即可。
要使用jQuery,我们只要要引入jQuery对应版本的pom依赖即可!
访问:只要是静态资源,SpringBoot就会去对应的路径寻找资源,我们这里访问:http://localhost:8080/webjars/jquery/3.4.1/jquery.js
那我们项目中要是使用自己的静态资源该怎么导入呢?
idea按两下shift,搜索WebAutoConfiguration - WebMvcAutoConfigurationAdapter - addResourceHandlers
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
// 第一种方式 webjars
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
// 第二种方式
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
ResourceProperties 可以设置和我们静态资源有关的参数;这里面指向了它会去寻找资源的文件夹,即staticLocation数组的内容。
所以得出结论,以下四个目录存放的静态资源可以被我们识别:
优先级从上到下依次降低
我们也可以自己通过配置文件来指定一下,哪些文件夹是需要我们放静态资源文件的,在application.yml中配置;
spring:
# 自定义资源文件的位置
resources:
static-locations: classpath:/coding/,classpath:/kuang/
一旦自己定义了静态文件夹的路径,原来的自动配置就都会失效了!
静态资源文件夹说完后,我们继续向下看源码!可以看到一个欢迎页的映射,就是我们的首页!
欢迎页,静态资源文件夹下的所有 index.html 页面;被 /** 映射。
比如我访问 http://localhost:8080/ ,就会找静态资源文件夹下的 index.html
新建一个 index.html ,在我们上面的3个目录中任意一个;然后访问测试 http://localhost:8080/ 看结果!
与其他静态资源一样,Spring Boot在配置的静态内容位置中查找 favicon.ico。如果存在这样的文件,它将自动用作应用程序的favicon。
关闭SpringBoot默认图标
spring:
# 关闭默认图标
mvc:
favicon:
enabled: false
自己放一个图标在静态资源目录下,我放在 public 目录下
清除浏览器缓存!刷新网页,发现图标已经变成自己的了!
其实jsp就是一个模板引擎,还有用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想都是一样的,什么样一个思想呢我们来看一下这张图:
模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。
通过查看源码,可知默认放在resources/templates包中,后缀为.html
这样就会被springboot自动识别了
引入依赖
org.springframework.boot
spring-boot-starter-thymeleaf
我们要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。
xmlns:th="http://www.thymeleaf.org"
thymeLeafController.java
@Controller
public class ThymeLeafController {
@RequestMapping("/thymeleaf")
public String thy(Model model) {
model.addAttribute("msg", "hello Thymeleaf
");
model.addAttribute("users", Arrays.asList("张三", "李四", "王五"));
// 后缀默认是 .html
return "/thymeLeafTest";
}
}
thymeLeafTest.html
Title
遍历一 推荐这么使用:
遍历二:
[[${user}]]
启动项目测试
手册网址:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.pdf
承接yml的上文,除了全局配置文件,我们还可以自己编写config配置类,加上@Configuration注解来让springBoot识别,覆盖掉默认的配置文件。
MyMvcConfig.java
// 如果想写一些定制化的功能,只要写这个组件,然后将他交给springBoot就会自动装配
// 因为类型要求为WebMvcConfigurer,所以我们实现其接口
// 可以使用自定义类扩展MVC的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
}
在application.properties文件中配置springmvc
点击源码,跳转进WebMvcProperties.java 文件
再定位到源码包中,找到WebMvcAutoConfiguration.java自动装配文件
通过@Conditional获知配置文件识别的条件,然后在自己的配置类中实现WebMvcConfigurer接口,并重写其中的addViewControllers()方法
package com.kuang.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Locale;
// 如果想写一些定制化的功能,只要写这个组件,然后将他交给springBoot就会自动装配
// 因为类型要求为WebMvcConfigurer,所以我们实现其接口
// 可以使用自定义类扩展MVC的功能
@Configuration
// 这个注解就是导入了一个类@Import(DelegatingWebMvcConfiguration.class),里面实现了WebMvcConfigurer,写了一些功能
// 会使我们自定义的配置类失效,@ConditionalOnClass()
@EnableWebMvc
public class MyMvcConfig implements WebMvcConfigurer {
// 将视图解析器交给SpringMVC
@Bean
public ViewResolver myViewResolver() {
return new MyViewResolver();
}
// 自定义了一个自己的视图解析器
public static class MyViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
System.out.println("这是我配置的视图解析器~~~~~~~~~");
return null;
}
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 浏览器发送/test , 就会跳转到test页面;
registry.addViewController("/test").setViewName("test");
}
}
启动项目测试, 可以看到我们配置的MyViewResolver注册进spring了
第1节后接第5节CRUD,之后可以穿插着看
做完以后总的项目结构
new project
等待依赖下载完成,创建包结构,实体类,dao层
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department implements Serializable {
private Integer id;
private String departmentName;
}
Employee类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee implements Serializable {
private Integer id;
private String lastName;
private String email;
private Integer gender;
private Department department;
private Date birth;
}
DepartmentDao
@Repository
public class DepartmentDao {
// 模拟数据库中的数据,无需创建数据库
private static Map departments = null;
static {
departments = new HashMap<>();
departments.put(101, new Department(101, "教学部"));
departments.put(102, new Department(102, "市场部"));
departments.put(103, new Department(103, "教研部"));
departments.put(104, new Department(104, "运营部"));
departments.put(105, new Department(105, "后勤部"));
}
//获得所有部门的信息
public Collection getDepartments() {
return departments.values();
}
// 通过id获取部门
public Department getDepartmentById(Integer id) {
return departments.get(id);
}
}
EmployeeDao
@Repository
public class EmployeeDao {
@Autowired
private DepartmentDao departmentDao;
// 模拟数据库中的数据,无需创建数据库
private static Map employees = null;
static {
employees = new HashMap<>();
employees.put(1001, new Employee(1001, "AA", "[email protected]", 0, new Department(101, "教学部"), new Date()));
employees.put(1002, new Employee(1002, "BB", "[email protected]", 1, new Department(102, "市场部"), new Date()));
employees.put(1003, new Employee(1003, "CC", "[email protected]", 0, new Department(103, "教研部"), new Date()));
employees.put(1004, new Employee(1004, "DD", "[email protected]", 1, new Department(104, "运营部"), new Date()));
employees.put(1005, new Employee(1005, "EE", "[email protected]", 1, new Department(105, "后勤部"), new Date()));
}
// 主键自增
private static Integer initId = 1006;
// 增加一个员工
public void saveEmp(Employee employee) {
if (employee.getId() == null) {
employee.setId(initId++);
}
employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
employees.put(employee.getId(), employee);
}
// 删除员工
public void deleteEmployeeById(Integer id) {
employees.remove(id);
}
// 查询全部员工信息
public Collection getAllEmp() {
return employees.values();
}
// 通过id查询员工
public Employee getEmployeeById(Integer id) {
return employees.get(id);
}
}
导入ThemeLeaf依赖
org.springframework.boot
spring-boot-starter-thymeleaf
将第5节从BootStrap模板复制过来的sign-in.html改名为,首页index.html
Signin Template for Bootstrap
导入ThemeLeaf约束
建议使用扩展MVC配置的首页访问方式,直接启动项目输入localhost:8080即可访问
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 访问首页,建议使用扩展MVC
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
//登录拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 配置自定义拦截器
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index", "/", "/user/login",
"/assets/**", "/dist/**", "/css/**", "/img/**", "/js/**");
}
}
创建LoginHandlerInterceptor,这里假设获取session中的username,如果存在就表示登录成功;不存在就表示登录失败,request中存失败msg
public class LoginHandlerInterceptor implements HandlerInterceptor {
/*
登录拦截器
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取用户名称,登录成功之后,应该有用户的session
Object inputEmail = request.getSession().getAttribute("email");
// 登录失败返会登录页
if (inputEmail == null) {
request.setAttribute("msg", "没有权限,请重新登录");
request.getRequestDispatcher("/").forward(request, response);
return false;
} else {
return true;
}
}
}
MyConfig中配置拦截器
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 访问首页,建议使用扩展MVC
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
//登录拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 配置自定义拦截器
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index", "/", "/user/login",
"/assets/**", "/dist/**", "/css/**", "/img/**", "/js/**");
}
}
resource下新建i18n文件夹,新建中英文的properties文件
index.html前端页面使用th:text="#{login.btn}"
等接收配置文件里的参数
参考上面的,我没写
自定义一个MyLocalResolver继承LocalResolver
public class MyLocalResolver implements LocaleResolver {
//解析国际化请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
String language = request.getParameter("language");
System.out.println("语言:" + language);
Locale locale = Locale.getDefault();
if (!Strings.isEmpty(language)) {
String[] split = language.split("_");
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
将组件注册进IOC容器
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 访问首页,建议使用扩展MVC
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
//登录拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 配置自定义拦截器
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index", "/", "/user/login",
"/assets/**", "/dist/**", "/css/**", "/img/**", "/js/**");
}
// 国际化解析器注册进组件
@Bean
public LocaleResolver localeResolver() {
return new MyLocalResolver();
}
}
BootStrap官网
可以直接下载全部模板,也可以挑选2个需要的页面下载,例如Dashboard和Sign-in
解压缩,将asserts和dist两个文件夹复制到static目录下,还可以新建个favicon.icon
再打开docs/4.0/examples目录,挑选需要的页面,复制到templates下面
启动项目,访问登录页面
新建commons.html,将Dashboard.html的顶部横幅、侧边栏剪切过来
Title
修改Dashboard.html,将commons.html的元素引入
Dashboard Template for Bootstrap
Dashboard
Section title
id
name
class
favourite
Header
1,001
Lorem
ipsum
dolor
sit
编写LoginController
@Controller
@RequestMapping("/user")
public class LoginController {
@RequestMapping("/login")
public String login(HttpServletRequest request,
@RequestParam("email") String email,
@RequestParam("password") String password) {
System.out.println("login方法");
request.getSession().setAttribute("email", email);
return "/dashboard";
}
@RequestMapping("/logout")
public String logout(HttpServletRequest request) {
System.out.println("logout方法");
request.getSession().removeAttribute("email");
return "/index";
}
}
index.html配置表单提交接口,调用登陆接口
登出按钮配置在commos的首页横幅中,调用登出接口
Sign out
启动项目测试
404页面Springboot有规定,在templates下新建error文件夹,再新建404.html即可
编写EmployeeController
@Controller
@RequestMapping("/Employee")
public class EmployeeController {
@Autowired
private EmployeeDao employeeDao;
@Autowired
private DepartmentDao departmentDao;
@GetMapping("/selectAll")
public String selectAll(Model model) {
System.out.println("selectAll方法");
Collection employees = employeeDao.getAllEmp();
model.addAttribute("emps", employees);
return "/employee/list";
}
}
新建list.html,从Dashboard.html复制,然后修改内容,编写表格
Dashboard Template for Bootstrap
启动项目测试
编写add.html
Title
在list.html添加add按钮
添加员工
Controller新加接口
@GetMapping("/toAdd")
public String toAdd(Model model) {
System.out.println("toAdd方法");
// 查出所有部门的信息
Collection departments = departmentDao.getDepartments();
model.addAttribute("departments", departments);
return "/employee/add";
}
@RequestMapping("/add")
public String add(Model model, Employee employee) {
System.out.println("add方法");
employeeDao.saveEmp(employee);
return "redirect:/Employee/selectAll";
}
启动测试
编写update.html
Title
在list.html添加update按钮
编辑
Controller新加接口
@GetMapping("/toUpdate/{id}")
public String toUpdate(@PathVariable("id") Integer id, Model model) {
System.out.println("toUpdate方法");
// 查出所有部门的信息
Collection departments = departmentDao.getDepartments();
model.addAttribute("departments", departments);
// 获取雇员
Employee employee = employeeDao.getEmployeeById(id);
model.addAttribute("emp", employee);
return "/employee/update";
}
@RequestMapping("/update")
public String update(Model model, Employee employee) {
System.out.println("update方法");
employeeDao.saveEmp(employee);
return "redirect:/Employee/selectAll";
}
启动测试
在list.html添加delete按钮
删除
Controller新加接口
// 删除员工
@GetMapping("/delete/{id}")
public String delete(@PathVariable("id") Integer id) {
System.out.println("delete方法");
employeeDao.deleteEmployeeById(id);
return "redirect:/Employee/selectAll";
}