首先新建项目,选择Spring Initializr
随便填一下包名,选版本号后点击Next即可
开启Spring Web服务。
这里需要注意一点,去修改Spring boot版本,使其小于3.0.5(如果其他配置与我前面配置一致的话),否则会报错
运行后发现Tomcat服务开启于8080端口,访问之
这是因为并没有写什么东西,接下来在这个主java文件新建文件夹controller
,并创建文件HelloController
,写一个hello
路由,内容如下
package com.example.qwq.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "Hello, Spring Boot !";
}
}
启动项目,访问**/hello**路由
在application.properties中写入内容如下
server.port=8888
此时重新运行项目,就会从8080端口变为8888端口
参考https://www.yuque.com/atguigu/springboot/qb7hy2即可
小trick分享:Alt+Insert可以快捷写出一些方法
首先写Dog.java
package com.qwq.cs;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Dog {
@Value("柯基")
private String name;
@Value("3")
private Integer age;
public Dog(){
}
public Dog(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
我们这里通过**@Value(‘xxx’)对实例化的类进行赋值,接下来去Test**文件夹下的java文件中进行调用
import com.qwq.cs.Dog;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class QwqApplicationTests {
@Autowired
private Dog dog;
@Test
void contextLoads() {
System.out.println(dog);
}
}
我们这里在cs文件夹下再写一个Person.java文件
package com.qwq.cs;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Component
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
public Person(){
}
public Person(String name, Integer age, Boolean happy, Date birth, Map<String, Object> maps, List<Object> lists, Dog dog) {
this.name = name;
this.age = age;
this.happy = happy;
this.birth = birth;
this.maps = maps;
this.lists = lists;
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", dog=" + dog +
'}';
}
}
而后,我们在src/resources
新建一个application.yaml
文件,写入内容如下
person:
name: quan9i
age: 19
happy: true
birth: 2023/4/17
maps: {k1: v1,k2: v2}
list:
-code
-guitar
-girl
dog:
name: 柯基
age: 3
而后我们在Person.java
中前面加上一句话
@ConfigurationProperties(prefix = "person")
//这个将配置文件中的值与java文件进行绑定,可以给其赋值
这个的话就是将值写入到person类中
此时会爆红,但不影响使用,接下来去Test
下的Java
文件中进行调用,只需把Dog
类换成Person
类即可
package com.qwq;
import com.qwq.cs.Dog;
import com.qwq.cs.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class QwqApplicationTests {
@Autowired
private Person person;
@Test
void contextLoads() {
System.out.println(person);
}
}
这里还需要做一点,就是设置文件编码格式为UTF-8
,否则就会报错(找了半小时,nnd)
而后运行即可
//加载特定配置文件
@PropertySource(value = "classpath:quan9i.properties")
public class Person {
@Value("${name}") //SPEL表达式取出配置文件值
java文件整体内容如下
import com.sun.org.apache.xpath.internal.operations.Bool;
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;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Component
//@ConfigurationProperties(prefix = "person")
//加载指定配置文件
@PropertySource(value = "classpath:quan9i.properties")
public class Person {
@Value("${name}")
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
public Person(){
}
public Person(String name, Integer age, Boolean happy, Date birth, Map<String, Object> maps, List<Object> lists, Dog dog) {
this.name = name;
this.age = age;
this.happy = happy;
this.birth = birth;
this.maps = maps;
this.lists = lists;
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", dog=" + dog +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
}
只要静态资源放在类路径下: called /static
(or /public
or /resources
or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
寻找方法如下:
双击Shift搜MVC,找到这个文件
而后找到自动配置类中的添加资源方法
自动映射 /webjars/**
接下来访问
将Maven方式的jquery复制下来,具体内容如下
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
然后粘贴到Pom.xml中,接下来可以发现自动加载Maven后,成功导入
访问地址:http://localhost:8080/webjars/jquery/3.4.1/jquery.js 后面地址要按照依赖里面的包路径
接下来看代码
发现这还有一个静态定义方法,跟进它这个**getStaticPathPattern()**方法进行查看
发现是根目录下的全部,然后接下来再回MVC这个文件中找一些其他的,这里发现WebProperties
发现三个其他目录,这里的话也就可以理解大致含义了,就是说在resources下新建resources、static、public目录,其下面的内容都可被直接访问
这里随便写一个1.js
,然后访问http://127.0.0.1:8888/1.js
他们的优先级顺序是resources>static(默认)>public
从WEBMVC文件中查看有关首页的
这里发现*getWelcomepage()*有关首页,然后它引用了getIndexHtml
函数,然后这个函数用了getResource
函数,这个函数引用了index.html
,那我们接下来在映射对应的目录下新建一个index.html
文件,按理说访问首页即可加载,接下来进行尝试
对于图标的话,直接在static文件下放置ico图标即可
这里的话接着说首页
首页的话它是需要用一个模板引擎进行数据交互的,这里用的是thymeleaf模板引擎,双击shift搜索Thymelaf
这里可以看到它是对templates文件夹下的所有.html
后缀的文件使用了这个模板,接下来进行尝试
尝试之前首先在pom.xml
中添加jar包
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
然后接下来在这个templates
目录下写个文件命名为test.html
。
然后我们想要主java文件去实现跳转到这个html界面,这个时候就需要用到一个controller
,其实就是新建一个Controller
文件夹,在里面写内容即可实现跳转。具体代码为
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//在templates目录下的所有文件,只能通过controller来跳转!
//这个需要模板引擎的支持,这里使用的是thymeleaf
@Controller
public class IndexController {
@RequestMapping("/test")
public String test() {
return "test";
}
}
他这里的话,是我们访问test
,然后它会返回test
,然后它会自动去拼接.html
后缀,然后去templates
下找是否存在此文件,如果存在,此时就会直接加载
接下来说一下thy这个模板的引用,它需要在我们的html文件头部首先声明
<html lang="en" xmlns:th="http://www.thymeleaf.org">
而后,对于一些值的引用,比如我们这里的java文件写入一个msg参数
package com.qwq.Controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
//在templates目录下的所有文件,只能通过controller来跳转!
//这个需要模板引擎的支持,这里使用的是thymeleaf
@Controller
public class IndexController {
@RequestMapping("/test")
public String test(Model model) {
model.addAttribute("msg","hello,Springboot");
return "test";
}
}
想调用的话,此时需要在html中声明th:text,具体代码如下
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${msg}"></h1>
</body>
</html>
实现效果
th:text 对参数值进行获取
th:utext 如果参数中含有<h1></h1>这种标签,会进行解析
th:each 遍历输出
表达式名字 | 语法 | 用途 |
---|---|---|
变量取值 | ${…} | 获取请求域、session域、对象等值 |
选择变量 | *{…} | 获取上下文对象值 |
消息 | #{…} | 获取国际化等值 |
链接 | @{…} | 生成链接 |
片段表达式 | ~{…} | jsp:include 作用,引入公共页面片段 |
条件运算
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
示例:java文件代码
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Arrays;
//在templates目录下的所有文件,只能通过controller来跳转!
//这个需要模板引擎的支持,这里使用的是thymeleaf
@Controller
public class IndexController {
@RequestMapping("/test")
public String test(Model model) {
model.addAttribute("msg","hello,Springboot");
model.addAttribute("users", Arrays.asList("quan9i","is","the","best"));
return "test";
}
}
主要是这一行
model.addAttribute("users", Arrays.asList("quan9i","is","the","best"));
然后接下来看html,其内容如下
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:each="user:${users}" th:text="${user}"></div>
</body>
</html>
th:each中用user挨个获取了users的参数名,然后呢,我们这里用th:text对它再进行挨个的值的输出,实现效果如下。
也可以这么写
<div th:each="user:${users}" >[[${user}]]</div>
查看Contentxx
在这个Contentxxx
中发现ViewResolver
解析器,跟进
public interface ViewResolver 实现了视图解析器的类,我们就可以认为是视图解析器,接下来继续跟进它内部的这个函数,我们将它这个函数名进行复制,然后看Contentxx
中哪里调用了这个
可以发现它这里是当内容非空时,getCandidateViews函数
先对其进行处理,而后用getBestView
函数处理,接下来首先跟进一下第一个函数
它这里的话其实就是遍历了所有的视图解析器,遍历完后封装为对象,添加到视图,而后返回视图。它这里最后的获取是需要通过bean来进行获取的
所以我们最后的示例代码如下
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.WebMvcConfigurer;
import java.util.Locale;
//想添加自定义功能,只需要写一个组件,而后交给Springboot,即可自动实现
//扩展Spring MVC
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//public interface ViewResolver 实现了视图解析器的类,我们就可以认为是视图解析器
@Bean
public ViewResolver myViewResolver(){
return new MyViewResolver();
}
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception{
return null;
}
}
}
实现视图跳转,示例代码如下
public class MyMvcConfig implements WebMvcConfigurer {
//视图跳转
@Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/quan").setViewName("/test");
}
}
这里的话,**/test**会直接匹配到我们的那个templates
下的test.html
文件,我们这里注册了一个视图,当访问/quan
时,就会跳转到对应html界面
这里因为我们没有设置参数,所以为空白
还有一个@EnableWebMvc,这个轻易不能开启,他会使得默认的mvc配置失效。
后续用到的index.html及其他代码可在https://getbootstrap.com/docs/4.0/examples/中进行获取
先写一下部门的基本参数(部门ID及部门昵称)
#Department.java
public class Department {
private Integer id;
private String departmentName;
}
配置一下pom.xml,导入lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
接下来放入java文件中,同时我们还要添加两个,一个是有参导入,一个是无参导入,代码如下
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.annotation.sql.DataSourceDefinition;
//部门表
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
private Integer id;
private String departmentName;
}
部门表写好后,此时我们还需要写一个员工表,此时新建一个文件,命名为Employee.java
文件,写一些基础的参数
#Employee.java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
//员工表
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender; //0代表女,1代表男
private Department department;
private Date bitrh;
}
接下来需要新建一个Dao
文件夹,然后这个我之前不太了解,百度了一下
在java学习中,特别是接触到web开发的时候,我们会经常遇到DAO这个家伙。中文名:数据访问对象,英文名:Data Access Object,我们简称DAO。在这一类的java后缀文件中,主要是用来访问数据库的,从数据库中选取需要分析或是处理的数据
然后接下来在它这个目录夹下新建文件命名为DepartmentDao.java
,内容如下
import com.qwq.pojo.Department;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
//部门dao
public class DepartmentDao {
//模拟数据库中的数据
private static Map<Integer, Department> departments = null;
static {
departments = new HashMap<Integer, Department>();//创建一个部门表
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<Department> getDepartments(){
return departments.values();
}
//查询部门所有id
public Department getDepartmentById(Integer id){
return departments.get(id);
}
接下来部门的写好了,还需要写一个员工的,所以再新建一个Employee.java
,内容如下
//员工Dao
@Repository
public class EmployeeDao {
//模拟数据库数据
private static Map<Integer, Employee> employees = null;
//员工所属部门
private DepartmentDao departmentDao;
static{
employees = new HashMap<Integer, Employee>();//创建一个部门表
employees.put(1001,new Employee(1001,"AA","A123@qq.com",0,new Department(1001,"教学部")));
employees.put(1001,new Employee(1002,"AA","B123@qq.com",1,new Department(1001,"市场部")));
employees.put(1001,new Employee(1003,"AA","C123@qq.com",0,new Department(1001,"教研部")));
employees.put(1001,new Employee(1004,"AA","D123@qq.com",1,new Department(1001,"运营部")));
employees.put(1001,new Employee(1005,"AA","E123@qq.com",0,new Department(1001,"后勤部")));
}
}
这里考虑到Date
不能直接写死,所以这里采用直接按时间生成的方式,修改Employee.java
内容如下
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
//员工表
@Data
@NoArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender; //0代表女,1代表男
private Department department;
private Date bitrh;
public Employee(Integer id, String lastName, String email, Integer gender, Department department) {
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
this.department = department;
this.bitrh = new Date();
//默认日期
}
}
然后此时就可以写入用户信息了,同时实现增删改查功能,EmployeeDao.java
内容如下
//员工Dao
@Repository
public class EmployeeDao {
//模拟数据库数据
private static Map<Integer, Employee> employees = null;
//员工所属部门
private DepartmentDao departmentDao;
static{
employees = new HashMap<Integer, Employee>();//创建一个部门表
employees.put(1001,new Employee(1001,"AA","A123@qq.com",0,new Department(1001,"教学部")));
employees.put(1001,new Employee(1002,"AA","B123@qq.com",1,new Department(1001,"市场部")));
employees.put(1001,new Employee(1003,"AA","C123@qq.com",0,new Department(1001,"教研部")));
employees.put(1001,new Employee(1004,"AA","D123@qq.com",1,new Department(1001,"运营部")));
employees.put(1001,new Employee(1005,"AA","E123@qq.com",0,new Department(1001,"后勤部")));
}
//主键自增!
private static Integer initId =1006;
//添加一个员工
public void save(Employee employee) {
if (employee.getId() == null)
employee.setId(initId++);
employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
employees.put(employee.getId(), employee);
}
//查询员工信息
public Collection<Employee> getAll() {
return employees.values();
}
//通过id查询员工
public Employee getEmployeeById(Integer id){
return employees.get(id);
}
//删除员工通过id
public void delete(Integer id){
employees.remove(id);
}
}
这里可以采用在时java文件中进行一个跳转的,当访问/
或/index.html
时强制跳转到index
,具体代码如下(但此方法并不推荐)
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping({"/","/index.html"})
public String index(){
return "index";
}
}
此时开启服务,访问
还有一种方法,就是我们可以通过写控制器来实现,具体步骤如下,新建MyMvcConfig
文件,具体内容如下
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 MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
}
此时再开启
同样也是可以访问到的,然后就是说一下静态资源的问题
在这里的话,所有的页面中的静态资源都需要用thymeleaf,
比如,在html文件开头,我们需要加上
<html lang="en" xmlns:th="http://www.thymeleaf.org">
在引用链接时,我们需要修改链接,具体如下
修改前: <link rel="stylesheet" href="./css/style.css">
修改后: <link rel="stylesheet" th:href=@{/css/style.css}>
什么是国际化呢,它在这里被我们称为i18n
,i18n实际上是国际化的英文缩写,中间有18个字符,故称为i18n,同类的还有K8s。国际化其实就是多语言模式,比如我们常见的网站都支持两种语言,一种是汉语,一种是英语。
接下来说一下具体操作,首先在根目录下新建文件夹,命名为i18n,此时新建文件,命名为login_zh_CN.properties
,按理说可以实现自动装配
如上图所示,不过我这里的话没实现,我是手动引入的,接下来继续看,添加英文模式,首先右键
接下来点击加号,输入en_US
而后点击OK,即可看见自动加入了英文,然后引入这个的话,是需要在application.yaml添加message
的,具体内容如下
server.port: 8888
#清除缓存
spring:
thymeleaf:
cache: false
#配置信息
messages:
basename: i18n.login
而后我们在login.properties中可以实时更改三个文件
我们配置后在index.html中更改如下
<!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" th:href="@{/favicon.ico}">
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin">
<img class="mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">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>
<a class="btn btn-sm">中文</a>
<a class="btn btn-sm">English</a>
</form>
</body>
</html>
开启服务后访问
此时已成功生效,接下来改其他的一些zh及en配置
接下来同理修改html代码,具体如下
<!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" th:href="@{/favicon.ico}">
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin">
<img class="mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<input type="text" class="form-control" th:placeholder="#{login.username}" required autofocus>
<input type="password" id="inputPassword" class="form-control" th:placeholder="#{login.password}" required>
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me">[[#{login.remember}]]
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">[[#{login.btn}]]</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm">中文</a>
<a class="btn btn-sm">English</a>
</form>
</body>
</html>
然后接下来配置国际化的语言,它这个的话去MVC这个文件下寻找
找到这个localeResolver
方法,可以看出大致含义是当有配置的时候,就按自定义配置来,当没有配置的时候,就按照默认的来。
所以接下来我们重写一个localeResolver
方法,我们在config
文件夹下新建一个MylocaleResolver
文件,内容如下
import org.springframework.cglib.core.Local;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
public class MyLocaleResolver implements LocaleResolver{
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
//获取请求中的参数链接
String language = request.getParameter("l");
Locale locale = Locale.getDefault();//如果没有就使用默认的;
//如果请求的参数携带了地区化的参数
if(!StringUtils.isEmpty(language)){
String[] split = language.split("_");
//国家,地区
locale = new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
而后我们还需要去MyMvcConfig.java
中配置@Bean
,这样才能使得这个函数生效,MyMvcConfig.java
内容如下
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
//自定义的国际化组件生效了
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}
接下来打开网站
点击English
首先我们更改login.html
中,添加如下代码
<form class="form-signin" th:action="@{/user/login}">
接下来在Controller文件夹中写入loginController.java
文件,通过RequestMapping
写入路由,通过ResponseBody
写入返回内容,具体内容如下
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class LoginController {
@RequestMapping("/user/login")
@ResponseBody
public String login(){
return "Ok";
}
}
接下来运行项目,随便填写一下登录信息
成功写入
接收参数的话,我们需要在html中加入name
字段,因此对html文件进行更改
<input type="text" name="username" class="form-control" th:placeholder="#{login.username}" required autofocus>
<input type="password" name="password" id="inputPassword" class="form-control" th:placeholder="#{login.password}" required>
然后接下来在LoginController.java
文件中更改内容,添加校验,当登录成功时跳转到另一界面,登录失败则仍在当前登录界面,这里的话保险起见,在这里加入**RequestParam()**用于接收参数。
具体内容如下
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.thymeleaf.util.StringUtils;
@Controller
public class LoginController {
@RequestMapping("/user/login")
public String login(
@RequestParam("username") String username,
@RequestParam("password") String password,
Model model){
//具体的业务;
if (!StringUtils.isEmpty(username) && "123456".equals(password)){
return "dashboard";
}else{
//告诉用户,登录失败
model.addAttribute("msg","登录失败");
return "index";
}
}
}
接下来写一下跳转的界面,即dashboard.html
文件,内容如下
<!doctype html>
<html lang="en">
<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" th:href="@{/favicon.ico}">
<title>Dashboard Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/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>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script th:href="@{/js/jquery-3.2.1.slim.min.js}" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script th:href="@{/js/jquery-3.2.1.slim.min.js}"><\/script>')</script>
<script th:href="@{/js/vendor/popper.min.js}"></script>
<script th:href="@{/js/bootstrap.min.js}"></script>
<!-- Icons -->
<script th:href="@{/js/feather.min.js}"></script>
<script>
feather.replace()
</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>
此时运行项目
点击登录后
成功进入后台,但此时如果输错密码,是没有提示的,所以我们需要再设置一个消息提示,当输入密码错误时回显错误信息。
此时再去index.html
下添加一行代码
//如果登录成功,则不显示消息(通过th:if进行判断的)
<P style="color: red"th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></P>
打开界面再次进行尝试
但此时的URL不是很美观
我们可以添加一个在MyMvcConfig.java
中添加一个视图
registry.addViewController("/main.html").setViewName("dashboard");
而后简单更改下LoginController.java
,加一个页面重定向
在Config文件下写入LoginHandleInterceptor.java
文件,内容如下
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.handler.Handler;
public class LoginHandlerlnterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception{
//登录成功后,应有用户的session
Object loginUser = request.getSession().getAttribute("loginUser");
if (loginUser==null){//没有登录
request.setAttribute("msg","没有权限,请登录");
request.getRequestDispatcher("/index.html").forward(request,response);//请求转发
return false;
}else{
return true;
}
}
}
这个是通过session来校验是否登录的,所以我们需要在登录成功后添加session,修改LoginController.java
内容如下
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@RequestMapping("/user/login")
public String login(
@RequestParam("username") String username,
@RequestParam("password") String password,
Model model, HttpSession session){
//具体的业务;
if (!StringUtils.isEmpty(username) && "123456".equals(password)){
session.setAttribute("loginUser",username);
return "redirect:/main.html";
}else{
//告诉用户,登录失败
model.addAttribute("msg","登录失败");
return "index";
}
}
}
而后我们这是自定义类,所以还需要在MyMvcConfig.java
下添加@Bean
注释,添加自定义函数,具体内容如下
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
//自定义的国际化组件生效了
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerlnterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/","/user/login","/css/**","/js/**","");
}
}
此时便已实现拦截器大致功能。
在前端加入[[${session.loginUser}]]
,可以输出用户名。