前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring boot 从0到0.1 part(1)

Spring boot 从0到0.1 part(1)

作者头像
用户9691112
发布2023-05-18 14:00:06
6290
发布2023-05-18 14:00:06
举报
文章被收录于专栏:quan9i的安全笔记

Day 01

第一个Spring boot项目

首先新建项目,选择Spring Initializr

image-20230417191927308
image-20230417191927308

随便填一下包名,选版本号后点击Next即可

image-20230417192001173
image-20230417192001173

开启Spring Web服务。

这里需要注意一点,去修改Spring boot版本,使其小于3.0.5(如果其他配置与我前面配置一致的话),否则会报错

image-20230417194753817
image-20230417194753817

运行后发现Tomcat服务开启于8080端口,访问之

image-20230417194859701
image-20230417194859701

这是因为并没有写什么东西,接下来在这个主java文件新建文件夹controller,并创建文件HelloController,写一个hello路由,内容如下

代码语言:javascript
复制
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**路由

image-20230417201240868
image-20230417201240868

简化配置

application.properties中写入内容如下

代码语言:javascript
复制
server.port=8888

此时重新运行项目,就会从8080端口变为8888端口

image-20230417201530817
image-20230417201530817

自动配置原理

参考https://www.yuque.com/atguigu/springboot/qb7hy2即可

Day02

属性赋值

小trick分享:Alt+Insert可以快捷写出一些方法

常规

首先写Dog.java

代码语言:javascript
复制
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文件中进行调用

代码语言:javascript
复制
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);
    }

}
image-20230418152912223
image-20230418152912223

方法二(application.yaml)

我们这里在cs文件夹下再写一个Person.java文件

代码语言:javascript
复制
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文件,写入内容如下

代码语言:javascript
复制
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中前面加上一句话

代码语言:javascript
复制
@ConfigurationProperties(prefix = "person")
//这个将配置文件中的值与java文件进行绑定,可以给其赋值

这个的话就是将值写入到person类中

image-20230418153337233
image-20230418153337233

此时会爆红,但不影响使用,接下来去Test下的Java文件中进行调用,只需把Dog类换成Person类即可

代码语言:javascript
复制
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)

image-20230418162728350
image-20230418162728350

而后运行即可

image-20230418162841939
image-20230418162841939

方法三(加载特定配置文件)

代码语言:javascript
复制
//加载特定配置文件
@PropertySource(value = "classpath:quan9i.properties")
public class Person {
    @Value("${name}") //SPEL表达式取出配置文件值

java文件整体内容如下

代码语言:javascript
复制
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;
    }
}
image-20230418170929266
image-20230418170929266

静态资源导入

静态资源目录

只要静态资源放在类路径下: called /static (or /public or /resources or /META-INF/resources

访问 : 当前项目根路径/ + 静态资源名

寻找方法如下:

双击Shift搜MVC,找到这个文件

image-20230418181930020
image-20230418181930020

而后找到自动配置类中的添加资源方法

image-20230418182124956
image-20230418182124956

webjar

自动映射 /webjars/**

接下来访问

https://www.webjars.org/

将Maven方式的jquery复制下来,具体内容如下

代码语言:javascript
复制
<dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.4.1</version>
        </dependency>

然后粘贴到Pom.xml中,接下来可以发现自动加载Maven后,成功导入

image-20230422223752399
image-20230422223752399

访问地址:http://localhost:8080/webjars/jquery/3.4.1/jquery.js 后面地址要按照依赖里面的包路径

接下来看代码

image-20230422230636938
image-20230422230636938

发现这还有一个静态定义方法,跟进它这个**getStaticPathPattern()**方法进行查看

image-20230422230733118
image-20230422230733118
image-20230422230743353
image-20230422230743353

发现是根目录下的全部,然后接下来再回MVC这个文件中找一些其他的,这里发现WebProperties

image-20230422230835307
image-20230422230835307
image-20230422230853715
image-20230422230853715

发现三个其他目录,这里的话也就可以理解大致含义了,就是说在resources下新建resources、static、public目录,其下面的内容都可被直接访问

image-20230422231159214
image-20230422231159214

这里随便写一个1.js,然后访问http://127.0.0.1:8888/1.js

image-20230422231258933
image-20230422231258933

他们的优先级顺序是resources>static(默认)>public

首页相关

从WEBMVC文件中查看有关首页的

image-20230422232202548
image-20230422232202548

这里发现*getWelcomepage()*有关首页,然后它引用了getIndexHtml函数,然后这个函数用了getResource函数,这个函数引用了index.html,那我们接下来在映射对应的目录下新建一个index.html文件,按理说访问首页即可加载,接下来进行尝试

image-20230422232519834
image-20230422232519834
image-20230422232601075
image-20230422232601075

对于图标的话,直接在static文件下放置ico图标即可

image-20230423001520233
image-20230423001520233

这里的话接着说首页

首页的话它是需要用一个模板引擎进行数据交互的,这里用的是thymeleaf模板引擎,双击shift搜索Thymelaf

image-20230423005819217
image-20230423005819217

这里可以看到它是对templates文件夹下的所有.html后缀的文件使用了这个模板,接下来进行尝试

尝试之前首先在pom.xml中添加jar包

代码语言:javascript
复制
<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文件夹,在里面写内容即可实现跳转。具体代码为

代码语言:javascript
复制
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";
    }
}
image-20230423011827162
image-20230423011827162

他这里的话,是我们访问test,然后它会返回test,然后它会自动去拼接.html后缀,然后去templates下找是否存在此文件,如果存在,此时就会直接加载

image-20230423012044971
image-20230423012044971

接下来说一下thy这个模板的引用,它需要在我们的html文件头部首先声明

代码语言:javascript
复制
<html lang="en" xmlns:th="http://www.thymeleaf.org">

而后,对于一些值的引用,比如我们这里的java文件写入一个msg参数

代码语言:javascript
复制
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,具体代码如下

代码语言:javascript
复制
<!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>

实现效果

image-20230423012827420
image-20230423012827420

thymeleaf部分语法

代码语言:javascript
复制
th:text 对参数值进行获取
th:utext 如果参数中含有<h1></h1>这种标签,会进行解析
th:each 遍历输出

表达式名字

语法

用途

变量取值

${…}

获取请求域、session域、对象等值

选择变量

*{…}

获取上下文对象值

消息

#{…}

获取国际化等值

链接

@{…}

生成链接

片段表达式

~{…}

jsp:include 作用,引入公共页面片段

条件运算

代码语言:javascript
复制
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue) 

示例:java文件代码

代码语言:javascript
复制
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";
    }
}

主要是这一行

代码语言:javascript
复制
model.addAttribute("users", Arrays.asList("quan9i","is","the","best"));

然后接下来看html,其内容如下

代码语言:javascript
复制
<!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对它再进行挨个的值的输出,实现效果如下。

image-20230423014216008
image-20230423014216008

也可以这么写

代码语言:javascript
复制
<div th:each="user:${users}" >[[${user}]]</div>

MVC相关

装配原理

查看Contentxx

image-20230423022041412
image-20230423022041412

在这个Contentxxx中发现ViewResolver解析器,跟进

image-20230423022129264
image-20230423022129264

public interface ViewResolver 实现了视图解析器的类,我们就可以认为是视图解析器,接下来继续跟进它内部的这个函数,我们将它这个函数名进行复制,然后看Contentxx中哪里调用了这个

image-20230423022258577
image-20230423022258577

可以发现它这里是当内容非空时,getCandidateViews函数先对其进行处理,而后用getBestView函数处理,接下来首先跟进一下第一个函数

image-20230423022425996
image-20230423022425996

它这里的话其实就是遍历了所有的视图解析器,遍历完后封装为对象,添加到视图,而后返回视图。它这里最后的获取是需要通过bean来进行获取的

所以我们最后的示例代码如下

代码语言:javascript
复制
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;
        }
    }
}
小扩展

实现视图跳转,示例代码如下

代码语言:javascript
复制
public class MyMvcConfig implements WebMvcConfigurer {

    //视图跳转
    @Override
    public void addViewControllers(ViewControllerRegistry registry){
        registry.addViewController("/quan").setViewName("/test");
    }
}

这里的话,**/test**会直接匹配到我们的那个templates下的test.html文件,我们这里注册了一个视图,当访问/quan时,就会跳转到对应html界面

image-20230423024335177
image-20230423024335177

这里因为我们没有设置参数,所以为空白

还有一个@EnableWebMvc,这个轻易不能开启,他会使得默认的mvc配置失效。

Day03(员工管理系统)

准备工作

后续用到的index.html及其他代码可在https://getbootstrap.com/docs/4.0/examples/中进行获取

先写一下部门的基本参数(部门ID及部门昵称)

代码语言:javascript
复制
#Department.java
public class Department {
    private Integer id;
    private String departmentName;
}

配置一下pom.xml,导入lombok

代码语言:javascript
复制
<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
</dependency>

接下来放入java文件中,同时我们还要添加两个,一个是有参导入,一个是无参导入,代码如下

代码语言:javascript
复制
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文件,写一些基础的参数

代码语言:javascript
复制
#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文件夹,然后这个我之前不太了解,百度了一下

代码语言:javascript
复制
在java学习中,特别是接触到web开发的时候,我们会经常遇到DAO这个家伙。中文名:数据访问对象,英文名:Data Access Object,我们简称DAO。在这一类的java后缀文件中,主要是用来访问数据库的,从数据库中选取需要分析或是处理的数据

然后接下来在它这个目录夹下新建文件命名为DepartmentDao.java,内容如下

代码语言:javascript
复制
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,内容如下

代码语言:javascript
复制
//员工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内容如下

代码语言:javascript
复制
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内容如下

代码语言:javascript
复制
//员工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);
        }
    }
image-20230424024341054
image-20230424024341054

首页实现

这里可以采用在时java文件中进行一个跳转的,当访问//index.html时强制跳转到index,具体代码如下(但此方法并不推荐)

代码语言:javascript
复制
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {
    @RequestMapping({"/","/index.html"})
    public String index(){
        return "index";
    }
}

此时开启服务,访问

image-20230424213828630
image-20230424213828630

还有一种方法,就是我们可以通过写控制器来实现,具体步骤如下,新建MyMvcConfig文件,具体内容如下

代码语言:javascript
复制
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");
    }
}
image-20230425195221094
image-20230425195221094

此时再开启

image-20230425195554800
image-20230425195554800

同样也是可以访问到的,然后就是说一下静态资源的问题

在这里的话,所有的页面中的静态资源都需要用thymeleaf

比如,在html文件开头,我们需要加上

代码语言:javascript
复制
<html lang="en" xmlns:th="http://www.thymeleaf.org">

在引用链接时,我们需要修改链接,具体如下

代码语言:javascript
复制
修改前:    <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,按理说可以实现自动装配

image-20230425202438350
image-20230425202438350

如上图所示,不过我这里的话没实现,我是手动引入的,接下来继续看,添加英文模式,首先右键

image-20230425202755432
image-20230425202755432

接下来点击加号,输入en_US

image-20230425202738766
image-20230425202738766

而后点击OK,即可看见自动加入了英文,然后引入这个的话,是需要在application.yaml添加message的,具体内容如下

代码语言:javascript
复制
server.port: 8888
#清除缓存
spring:
  thymeleaf:
    cache: false
  #配置信息
  messages:
    basename: i18n.login

而后我们在login.properties中可以实时更改三个文件

image-20230425213412303
image-20230425213412303

我们配置后在index.html中更改如下

代码语言:javascript
复制
<!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">&copy; 2017-2018</p>
    <a class="btn btn-sm">中文</a>
    <a class="btn btn-sm">English</a>
</form>
</body>
</html>

开启服务后访问

image-20230425223920321
image-20230425223920321

此时已成功生效,接下来改其他的一些zh及en配置

image-20230425224115658
image-20230425224115658

接下来同理修改html代码,具体如下

代码语言:javascript
复制
<!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">&copy; 2017-2018</p>
    <a class="btn btn-sm">中文</a>
    <a class="btn btn-sm">English</a>
</form>
</body>
</html>
image-20230425224600652
image-20230425224600652

然后接下来配置国际化的语言,它这个的话去MVC这个文件下寻找

image-20230425225054702
image-20230425225054702

找到这个localeResolver方法,可以看出大致含义是当有配置的时候,就按自定义配置来,当没有配置的时候,就按照默认的来。

所以接下来我们重写一个localeResolver方法,我们在config文件夹下新建一个MylocaleResolver文件,内容如下

代码语言:javascript
复制
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内容如下

代码语言:javascript
复制
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();
    }
}

接下来打开网站

image-20230425232058034
image-20230425232058034

点击English

image-20230425232110138
image-20230425232110138

登录界面实现

首先我们更改login.html中,添加如下代码

代码语言:javascript
复制
<form class="form-signin" th:action="@{/user/login}">

接下来在Controller文件夹中写入loginController.java文件,通过RequestMapping写入路由,通过ResponseBody写入返回内容,具体内容如下

代码语言:javascript
复制
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";
        }
}
image-20230427003130661
image-20230427003130661

接下来运行项目,随便填写一下登录信息

image-20230427002956170
image-20230427002956170

成功写入

接收参数的话,我们需要在html中加入name字段,因此对html文件进行更改

代码语言:javascript
复制
<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()**用于接收参数。

具体内容如下

代码语言:javascript
复制
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文件,内容如下

代码语言:javascript
复制
<!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>

此时运行项目

image-20230427013449098
image-20230427013449098

点击登录后

image-20230427013507069
image-20230427013507069

成功进入后台,但此时如果输错密码,是没有提示的,所以我们需要再设置一个消息提示,当输入密码错误时回显错误信息。

此时再去index.html下添加一行代码

代码语言:javascript
复制
//如果登录成功,则不显示消息(通过th:if进行判断的)
<P style="color: red"th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></P>

打开界面再次进行尝试

image-20230427020436561
image-20230427020436561

但此时的URL不是很美观

我们可以添加一个在MyMvcConfig.java中添加一个视图

代码语言:javascript
复制
registry.addViewController("/main.html").setViewName("dashboard");
image-20230427022442106
image-20230427022442106

而后简单更改下LoginController.java,加一个页面重定向

image-20230427023918136
image-20230427023918136

登录拦截器

Config文件下写入LoginHandleInterceptor.java文件,内容如下

代码语言:javascript
复制
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内容如下

代码语言:javascript
复制
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注释,添加自定义函数,具体内容如下

代码语言:javascript
复制
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}]],可以输出用户名。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023/04/17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Day 01
    • 第一个Spring boot项目
      • 简化配置
    • 自动配置原理
    • Day02
      • 属性赋值
        • 常规
        • 方法二(application.yaml)
        • 方法三(加载特定配置文件)
      • 静态资源导入
        • 静态资源目录
        • webjar
      • 首页相关
        • thymeleaf部分语法
      • MVC相关
      • Day03(员工管理系统)
        • 准备工作
          • 首页实现
            • 国际化
              • 登录界面实现
                • 登录拦截器
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档