SpringBoot初学项目(一)

SpringBoot 项目Demo

1.创建项目

在idea中创建项目,勾选web模块和模板引擎Thymeleaf

image-20210504140740606

image-20210504140813433

image-20210504140821575

2.项目层次

在com.gip下建包,因为是demop,所以server层就省去了

image-20210504141042672

image-20210504141154792

导入前端页面模板(这里采用bootstrap官网模板),自己写也可以(无非就是登陆界面加表单)

image-20210504141414704

image-20210504141502306

3.项目功能

index.html:登录界面

dashboar.html:表单界面,用于展示数据

404.html:错误处理页面

登录界面效果:(后续需要修改)

image-20210504141710207

项目是展示员工数据的,所以要创建员工实体类,由于不同员工所属不同部门,所以还需要一个部门类,这里用到了一对多关系映射。登录系统的用户也可以创建一个实体类(这里就省去了)主要目的是展示下员工数据就行

4.创建对应的实体类

image-20210504235509018

package com.gip.pojo;

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 Date birth;
    private Department department;
}

复制代码
package com.gip.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private Integer id;
    private String DepartmentName;
}

复制代码

需要使用lombook插件

导入

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

复制代码

5.添加数据

这里在dao层伪造下数据

package com.gip.dao;

import com.gip.pojo.Department;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;


public class DepartmentDao {
    //使用HashMap<>来存伪造数据
    private  static Map<Integer,Department> departments = null;
    static {
        departments=new HashMap<Integer,Department>();
        departments.put(1,new Department(1,"市场部"));
        departments.put(2,new Department(2,"行政部"));
        departments.put(3,new Department(3,"技术部"));
        departments.put(4,new Department(4,"运营部"));
        departments.put(5,new Department(5,"后勤部"));
    }

    //获取所有部门信息
    public Collection<Department> getAllDepartments(){
        return departments.values();
    }

    //查询部门信息,通过id查询
    public Department findDepartmentById(int id){
        return departments.get(id);
    }
}

复制代码
package com.gip.dao;

import com.gip.pojo.Department;
import com.gip.pojo.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Repository
public class EmployeeDao {
    @Autowired
    private  DepartmentDao departmentDao;
    //使用Map来存数据
    private static Map<Integer, Employee> employees=null;
    static {
        employees=new HashMap<Integer, Employee>();
        employees.put(1001,new Employee(1001,"gip1","7882@qq.com",1,new Date(),new Department(1,"市场部")));
        employees.put(1002,new Employee(1002,"gip2","7882@qq.com",0,new Date(),new Department(2,"行政部")));
        employees.put(1003,new Employee(1003,"gip3","7882@qq.com",1,new Date(),new Department(3,"技术部")));
        employees.put(1004,new Employee(1004,"gip4","7882@qq.com",0,new Date(),new Department(4,"运营部")));
        employees.put(1005,new Employee(1005,"gip5","7882@qq.com",1,new Date(),new Department(5,"后勤部")));
    };

    //模拟主键自己增加
    private static Integer initId = 1006;

    //添加员工
    public void save(Employee employee){
        if(employee.getId()==null){
            employee.setId(initId++);
        }
        employee.setDepartment(departmentDao.findDepartmentById(employee.getDepartment().getId()));
        employees.put(employee.getId(),employee);
    }

    //查询全部员工
    public Collection<Employee> getAllEmployee(){
        return employees.values();
    }

    //通过id查找员工
    public Employee findEmployeeById(int id){
        return employees.get(id);
    }

    //通过id删除员工
    public void deleteEmployeeById(int id){
        employees.remove(id);
    }
}

复制代码

6.测试方法

在test目录下建立com.gip.dao包目的是为了测试文件与测试的类的位置相对应

image-20210505113723709

7.登录控制

首先启动springboot模板引擎的支持开启

添加starter

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
复制代码

application.properties中添加配置

#关闭模板引擎的缓存
spring.thymeleaf.cache=false
复制代码

在html中添加命名空间

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

使用方法

www.thymeleaf.org/doc/tutoria…

写一个跳转方法

package com.gip.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {
    @RequestMapping("/")
    public String login(){
        return "index";
    }
}

复制代码

运行项目,浏览器输入http://localhost:8080/

项目一打开能直接进入index界面

image-20210505225247675

登录界面

<!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="@{css/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" th:action="@{/login}">
      <img class="mb-4" th:src="@{css/icon.jpg}" alt="" width="72" height="72">
      <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
      <label for="inputEmail" class="sr-only">User</label>
      <input type="text" id="inputEmail" class="form-control" placeholder="User" required autofocus name="user">
      <label for="inputPassword" class="sr-only">Password</label>
      <input type="password" id="inputPassword" class="form-control" placeholder="Password" required name="pwd">
      <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>
    </form>
  </body>
</html>

复制代码

8.数据展示

展示界面

image-20210505225455454

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>show数据</title>
    <style type="text/css">
        table.gridtable {
            font-family: verdana,arial,sans-serif;
            font-size:11px;
            color:#333333;
            border-width: 1px;
            border-color: #666666;
            border-collapse: collapse;
            margin: auto;
            text-align: center;
        }
        table.gridtable th {
            border-width: 1px;
            padding: 8px;
            border-style: solid;
            border-color: #666666;
            background-color: #dedede;
        }
        table.gridtable td {
            border-width: 1px;
            padding: 8px;
            border-style: solid;
            border-color: #666666;
            background-color: #ffffff;
        }
    </style>
    <!-- Bootstrap core CSS -->
    <link th:href="@{css/bootstrap.min.css}" rel="stylesheet">
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div>
    <div class="text-primary" th:text="'当前登录用户是:'+${session.user}"></div>
    <a class="btn btn-primary" th:href="@{/add}">添加员工</a>
    <div style="text-align: center"><h3>展示员工数据</h3></div>
    <table class="gridtable">
        <tr>
            <th>员工编号</th><th>员工姓名</th><th>性别</th><th>部门</th>
        </tr>
        <tr th:each="emp:${eData}">
            <td th:text="${emp.getId()}">Text 1A</td><td th:text="${emp.getLastName()}">Text 1B</td><td th:text="${emp.getGender()==0?'女':'男'}">Text 1C</td><td th:text="${emp.getDepartment().getDepartmentName()}">Text 1C</td>
        </tr>

    </table>
</div>
</body>
</html>
复制代码

contoller层代码

package com.gip.controller;

import com.gip.dao.DepartmentDao;
import com.gip.dao.EmployeeDao;
import com.gip.pojo.Employee;
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.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(@RequestParam("user") String user, @RequestParam("pwd") String pwd, Model model, HttpSession session){
        System.out.println(user);
        System.out.println(pwd);
        session.setAttribute("user",user);
//        model.addAttribute("user",user);
        model.addAttribute("eData",new EmployeeDao().getAllEmployee());
        return "show";
    }
    @RequestMapping("/add")
    public String gotoAdd(Model model){
        model.addAttribute("Departments",new DepartmentDao().getAllDepartments());
        return "add";
    }

    @RequestMapping("/addEmployee")
    public String addEmployee(Employee employee){
        System.out.println(employee);
        return "show";
    }
}

复制代码

9.数据添加

添加用户

image-20210505225547547

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>show数据</title>
    <style>
        .addFrom {
            width: 50%;
            margin: auto;
        }
    </style>
    <!-- Bootstrap core CSS -->
    <link th:href="@{css/bootstrap.min.css}" rel="stylesheet">
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div>
    <a class="btn btn-primary" th:href="@{/add}">添加员工</a>
    <a class="btn btn-primary">展示员工</a>
    <div style="text-align: center"><h3>添加员工数据</h3></div>
    <form class="addFrom" th:action="@{/addEmployee}" method="post">
        <div class="form-group">
            <label for="exampleFormControlInput1">User ID</label>
            <input type="text" class="form-control" id="exampleFormControlInput1" placeholder="User ID" name="id">
        </div>
        <div class="form-group">
            <label for="exampleFormControlInput1">User Name</label>
            <input type="text" class="form-control" id="exampleFormControlInput2" placeholder="User Name"
                   name="lastName">
        </div>
        <div class="form-group">
            <label for="exampleFormControlSelect1">Select Department</label>
            <select class="form-control" id="exampleFormControlSelect1" style="height: 35px" name="department.id">
                <option th:each="department:${Departments}" th:text="${department.getDepartmentName()}"
                        th:value="${department.getId()}">1
                </option>
            </select>
        </div>
        <div class="form-group">
            <label for="exampleFormControlSelect1">Select Gender</label>
            <select class="form-control" id="exampleFormControlSelect2" style="height: 35px" name="gender">
                <option value="0"></option>
                <option value="1"></option>
            </select>
        </div>
        <div class="form-group">
            <input type="submit" class="btn-primary btn">
        </div>
    </form>
</div>
</body>
</html>
复制代码

顺带一提:idea格式化快捷键ctrl+alt+L

注意:

image-20210505225727629

这里为什么值传递id,因为后台接收对象是employee

image-20210505225759499

这个对象里面嵌套了一个部门对象,idea无法在一个表单中做对象映射(所以要传递部门对象的一个属性,如果要传递整个部门对象要再做一次封装,或在嵌套一个表单实现!)

传递对象打印如下

image-20210505230012629

测试下:

image-20210505232312004

image-20210505232444790

10.国际化

springboot为我们提供了国际化的操作。

在resources目录下创建i18n文件夹,创建login资源包

i18n是国际化单词的缩写,首字母i,尾字母n,中间隔了18个字母

提示后面login_zh_CN会自动归类到资源包下,zh_CN代表:中文,中国;en_US代表英文:美国

image-20210505234640627

快捷操作:

image-20210505234943066

image-20210505235103135

使用方法:

springboot配置中指定国际化所在的文件(springboot默认国际化文件是messages)

spring.messages.basename=i18n/login
复制代码

不指定效果如下:

image-20210505235316556

image-20210505235144732

可以发现使用th:语法加上#修饰符,{}来使用国际化元素

正确效果如下:

image-20210505235438715

使用到的元素都会高亮哦

image-20210505235656451

  • 提示:如果只是页面修改,项目只用重新build一下就行,不需要重新启动
  • 快捷键:Ctrl+F9

如何切换国际化语言呢?

一般情况是默认跟随浏览器语言的,或者是识别浏览器发出的请求头,一般请求头就带有语言的标识。springboot默认已经实现了该功能,如果想自行切换可以使用链接的方式发送请求,后台自行编写解析locale的类来处理请求。

建立一个在config包下MyLocaleResolver.java类要实现LocaleResolver接口

package com.gip.config;

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 httpServletRequest) {
        String l = httpServletRequest.getParameter("l");
        Locale locale=Locale.getDefault();
        if(!StringUtils.isEmpty(l)){
            String[] split = l.split("_");
            locale=new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}

复制代码

然后将其注册到配置类中(用了@Configuration的类)

image-20210506001744477

这个localeResolver名字是固定的,生成的bean就叫localeResolver才可以生效(可能是这样springboot才能识别到,或者覆盖添加)

之后,我们在登录界面添加两行切换的a链接

  	<a class="btn btn-primary" th:href="@{/(l='zh_CN')}">中文</a>
    <a class="btn btn-primary" th:href="@{/(l='en_US')}">英文</a>
复制代码

模板语法:@{}里面写的就是链接的地址,如果想要带参数直接写(参数名=参数值)

想带多个参数这样写!!!(逗号隔开就行):th:href="https://juejin.cn/post/@{/(l='zh_CN',z='hh')}"

ok到页面测试

image-20210506002421129

image-20210506002455645

image-20210506002505008

11.数据删除

controller中添加删除方法

    @RequestMapping("/delete/{id}")
    public String deleteEmployee(@PathVariable("id") int id){
        employeeDao.deleteEmployeeById(id);
        return "redirect:/show";
    }
复制代码

注意使用resultful风格时候如果{参数名}和方法接收的形参名不一致的话

要使用@PathVariable注解对应上去

在页面上新增a链接可以请求到删除方法

<td><a class="btn btn-danger" th:href="@{'/delete/'+${emp.getId()}}">删除</a></td>
复制代码

注意拼接格式:th:href="https://juejin.cn/post/@{'/delete/'+${emp.getId()}}"

image-20210506122849898

image-20210506122904371

12.登录拦截器

首先在config包下新建LoginHandlerInterceptor类

package com.gip.config;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object user = request.getSession().getAttribute("user");
        if(user==null){
            request.setAttribute("msg","没有登录,请先登录!");
            request.getRequestDispatcher("/").forward(request,response);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

复制代码

image-20210506203808340

先取session 中用户信息,不为空代表已登录了,为空的话就转发到首页(登录界面),并且request携带参数msg作为提示信息供前台接收。

在自己配置类中,重写方法addInterceptors

image-20210506204001143

添加拦截器,过滤的请求地址,以及排除过滤的地址

注意:要排除过滤静态资源请求

可以去配置文件看这个# spring 静态资源扫描路径 spring.resources.static-locations=classpath:/static/

之后就可以写成:/static/**

新增一个地址映射

  registry.addViewController("/main").setViewName("show");
复制代码

未登录状态,输入/main,发现拦截器生效,页面被转发到首页

image-20210506205757775

13.修改数据

同理

controller中新增修改方法

    @RequestMapping("goUpdate")
    public String goUpdate(int id,Model model) {
        Employee employee = employeeDao.findEmployeeById(id);
        model.addAttribute("employee",employee);
        model.addAttribute("Departments", new DepartmentDao().getAllDepartments());
        return "update";
    }

    @RequestMapping("/updateEmployee")
    public String updateEmployee(Employee employee) {
        employeeDao.save(employee);
        return "redirect:/show";
    }
复制代码

跳转到修改界面,携带id

<td><a class="btn btn-danger" th:href="@{/goUpdate(id=${emp.getId()})}">修改</a></td>
复制代码

update界面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>update数据</title>
    <style>
        .addFrom {
            width: 50%;
            margin: auto;
        }
    </style>
    <!-- Bootstrap core CSS -->
    <link th:href="@{css/bootstrap.min.css}" rel="stylesheet">
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div>
    <a class="btn btn-primary" th:href="@{/add}">添加员工</a>
    <a class="btn btn-primary">展示员工</a>
    <div style="text-align: center"><h3>修改员工数据</h3></div>
    <form class="addFrom" th:action="@{/updateEmployee}" method="post">
        <div class="form-group">
            <label for="exampleFormControlInput1">User ID</label>
            <input type="hidden" readonly class="form-control" placeholder="User ID" name="id"
                   th:value="${employee.getId()}">
            <input type="text" readonly class="form-control" id="exampleFormControlInput1" placeholder="User ID"
                   name="id" th:value="${employee.getId()}">
        </div>
        <div class="form-group">
            <label for="exampleFormControlInput1">User Name</label>
            <input type="text" class="form-control" id="exampleFormControlInput2" placeholder="User Name"
                   th:value="${employee.getLastName()}"
                   name="lastName">
        </div>
        <div class="form-group">
            <label for="exampleFormControlSelect1">Select Department</label>
            <select class="form-control" id="exampleFormControlSelect1" style="height: 35px" name="department.id">
                <option th:each="department:${Departments}" th:text="${department.getDepartmentName()}"
                        th:value="${department.getId()}"
                        th:selected="${employee.getDepartment().getId()==department.getId()}">1
                </option>
            </select>
        </div>
        <div class="form-group">
            <label for="exampleFormControlSelect1">Select Gender</label>
            <select class="form-control" id="exampleFormControlSelect2" style="height: 35px" name="gender">
                <option value="0" th:selected="${employee.getGender()==0}"></option>
                <option value="1" th:selected="${employee.getGender()==1}"></option>
            </select>
        </div>
        <div class="form-group">
            <label for="exampleFormControlInput1">Birth</label>
            <input type="text" class="form-control" id="exampleFormControlInput3"
                   th:value="${#dates.format(employee.getBirth(),'yyyy-MM-dd')}"
                   name="birth">
        </div>
        <div class="form-group">
            <input type="submit" class="btn-primary btn">
        </div>
    </form>
</div>
</body>
</html>
复制代码

image-20210506221945161

显示id的控件input,如何让其不被修改?

使用disabled不可取:因为这样完全禁用,前台是不会传递这个控件的值到后台去

所以使用readonly属性即可!(只读,不可选择修改)

或者添加一个隐藏域传递id

type=”hidden”

<input type="hidden" readonly class="form-control" placeholder="User ID" name="id"
       th:value="${employee.getId()}">
<input type="text" readonly class="form-control" id="exampleFormControlInput1" placeholder="User ID"
       name="id" th:value="${employee.getId()}">
复制代码

Listen,坑点来了

日期拿到前台要处理下格式

格式如下:

th:value="${#dates.format(employee.getBirth(),'yyyy-MM-dd')}"
复制代码

如何要修改的话

方法1:

记得添加配置

spring.mvc.format.date=yyyy-MM-dd
复制代码

因为springboot默认的格式是yyyy/MM/dd

/分割的!

想改成-分割要设置

方法2:

在实体类中

添加注解 @DateTimeFormat(pattern="yyyy-MM-dd")

和加个配置

#spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
#spring.jackson.time-zone=GMT+8
复制代码

都要写否则报错,这个配置是如果json传递的话,能按照格式解析!

可以用这个@JsonFormat注解代替

image-20210506222749429

如果前端传入的参数是 json 那我们就要加上@JsonFormat(pattern=“yyyy-MM-dd HH:mm:ss”, timezone = “GMT+8”), pattern = “yyyy-MM-dd HH:mm:ss”表示你要接收时间类型,timezone = “GMT+8”(因为时间相差8小时问题,所以要加上这个属性)

终于大功告成,测试一波!

修改前

image-20210506223013152

修改后

image-20210506223127403

image-20210506223150031

顺带提一嘴:

image-20210506224344336

这个false一定要写,否则写其他路径会解析出错,其他路径会导致报错!!!,搞死我(有些人觉得没必要,结果后面有坑)所以要写!

14.404处理

springboot提供了很好方式:

image-20210506224659573

在templates下创建error下放html文件

html文件名就用响应码来命名:例如:404,500

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享