SpringBootWEB开发

SpringBootWEB开发

1、静态资源导入

1.1、第一种方式使用webjars

官网](https://www.webjars.org/) 找一个jQuery示例

WebMvcAutoConfiguration中关于静态资源的源码部分

public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!this.resourceProperties.isAddMappings()) {//如果你在resourceProperties配置文件中自定义了静态资源的路径,那么直接默认的就无效了
        logger.debug("Default resource handling disabled");
    } else {
        this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");   //第一种使用webjars,要找的静态资源就在这个目录下
        this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
           //第二种在这里,找resourceProperties中配置好的默认位置 registration.addResourceLocations(this.resourceProperties.getStaticLocations());
            if (this.servletContext != null) {
                ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
                registration.addResourceLocations(new Resource[]{resource});
            }

        });
    }
}

解释:
- addResourceHandlers(ResourceHandlerRegistry registry):这是一个公共方法,用于添加资源处理器。参数registry是资源处理器注册器。

- if (!this.resourceProperties.isAddMappings()):如果不添加映射,就记录一条调试信息。

- this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/"):添加一个资源处理器,处理路径为/webjars/**的请求,资源位置在classpath:/META-INF/resources/webjars/。

- this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {...}):添加另一个资源处理器,处理路径由mvcProperties.getStaticPathPattern()获取,资源位置由resourceProperties.getStaticLocations()获取。如果servletContext不为空,还会添加一个ServletContextResource资源。

在官网上复制maven依赖

<dependency>
            <groupId>org.webjars.npm</groupId>
            <artifactId>jquery</artifactId>
            <version>3.7.0</version>
</dependency>

导入依赖,导入后可以看到目录结构,访问localhost:8080/webjars/jquery/3.7.0/dist/jquery.js 就可以访问到这个静态资源。
在这里插入图片描述
在这里插入图片描述

1.2、spring boot默认约定好的资源路径

在WebProperties源码中有Resources静态类,里面指明了资源路径

  • classpath:/META-INF/resources/,就是第一种方法中webjars的上一级
  • classpath:/resources/,优先级最高,这里放一些上传的资源
  • classpath:/static/,优先级次之,默认静态资源放这里
  • classpath:/public/。优先级最低,这里放一些公共的资源
 public static class Resources {
        private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
        private String[] staticLocations;
        private boolean addMappings;
        private boolean customized;
        private final WebProperties.Resources.Chain chain;
        private final WebProperties.Resources.Cache cache;

        public Resources() {
            this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
            this.addMappings = true;
            this.customized = false;
            this.chain = new WebProperties.Resources.Chain();
            this.cache = new WebProperties.Resources.Cache();
        }
		//在这里上面定义的资源路径可以被调用,registration.addResourceLocations(this.resourceProperties.getStaticLocations());从这里点过来的getStaticLocations()方法
        public String[] getStaticLocations() {
            return this.staticLocations;
        }
-------------------此处省略后面源码
 }

优先级测试

在resources目录中再创建public、resource目录,分别在这三个目录中各建一个1.js里面内容为,public、resource、static

访问:localhost:8080/1.js

在这里插入图片描述

可以看出resource优先级最高,现在把resource的js文件删除再访问,发现变成static,说明static是第二优先。

在这里插入图片描述

原理:静态映射/**

静态资源和请求如果相同的话,会先找请求的Controller看能不能处理,不能处理的话将这些请求 交给静态资源处理器处理,要是静态资源处理器还不能找到就404了。

比如:在resource目录下建一个2.js文件,然后写一个controller让它的请求路径也写成2.js然后返回aaaa

那么在访问localhost:8080/2.js时就会显示的是aaaa

访问静态资源前加前缀

一般静态资源与请求会区分开,请求会经过拦截器进行判断,因为静态资源通常不涉及到业务逻辑处理没有必要再经过拦截器,为了与请求区分开,就会给静态资源搞一个特殊的前缀,默认映射的是/**,我们可以在配置文件中更改。

spring.mvc.static-path-pattern=/resources/**

这样在访问静态资源时都要加上resources才能拿到

如:localhost:8080/resources/1.js才能访问到

2、首页如何定制

​ Spring Boot 支持静态和模板化的欢迎页面。 它首先在配置的静态内容位置中查找文件。 如果未找到模板,则查找模板。 如果找到任一,它将自动用作应用程序的欢迎页面。index.html index

也就是说,index.html可以放在静态资源里哪一个目录都可以,也可以使用controller处理index请求让它到指定的页面当首页。

但是,如果放在templates下的话只能使用controller让它返回到index.html

在这里插入图片描述

使用controller就需要视图解析器了,spring boot中需要使用thymeleaf模板引擎

自定义图标

与其他静态资源一样,Spring 引导会检查配置的静态内容位置中是否有 。 如果存在此类文件,则会自动将其用作应用程序的图标。favicon.ico

这里随便弄个图片命名为favicon.ico,把它放在static目录里,统一一下index.html也放进去

重启之前清理一些浏览器缓存。

这个图片前后端分离基本上就是前端做的了,spring boot都已经弃用了。

3、模板引擎thymeleaf

3.1、Thymeleaf简介

​ Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。它与 JSP,Velocity,FreeMaker 等模板引擎类似,也可以轻易地与 Spring MVC 等 Web 框架集成。与其它模板引擎相比,Thymeleaf 最大的特点是,即使不启动 Web 应用,也可以直接在浏览器中打开并正确显示模板页面 。

​ Thymeleaf 是新一代 Java 模板引擎,与 Velocity、FreeMarker 等传统 Java 模板引擎不同,Thymeleaf 支持 HTML 原型,其文件后缀为“.html”,因此它可以直接被浏览器打开,此时浏览器会忽略未定义的 Thymeleaf 标签属性,展示 thymeleaf 模板的静态页面效果;当通过 Web 应用程序访问时,Thymeleaf 会动态地替换掉静态内容,使页面动态显示。

Thymeleaf 通过在 html 标签中,增加额外属性来达到“模板+数据”的展示方式,

先导入依赖

 <dependency><!--页面模板依赖-->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

找源码ThymeleafProperties

public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    ............
}

分析源码,默认的前缀为classpath:/templates/,默认的后缀为 “.html”,所以将html文件放在templates的目录下,然后用controller处理请求跳转到指定页。

测试:在templates目录下新建test.html,然后写一个controller

@RestController
public class TestController {
    @RequestMapping("/t")
    public String test(Model model){
        model.addAttribute("msg","嗨嗨嗨,Thymeleaf");
        return "test";
    }
}

test.html,引入头文件:,用${}取变量

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
<!--所有的html元素都可以被Thymeleaf接管  th:元素名-->
<div th:text="${msg}"></div>
</body>
</html>

1235456

3.2、请求处理-常用参数注解的使用

  • @PathVariable路径变量

    新建ParameterTestController测试

    @RequestMapping("/car/{id}/owenr/{username}")
    public Map<String,Object> getCar(@PathVariable("id") Integer id,
                                     @PathVariable("username") String name,
                                     @PathVariable Map<String,String> pv){
    
        Map<String, Object> map = new HashMap<>();
        map.put("id",id);
        map.put("name",name);
        map.put("pv",pv);
        return map;
    }
    

image-20230718093337721

  • @RequestHeader获取请求头

    @RequestMapping("/car/{id}/owenr/{username}")
    public Map<String,Object> getCar(@PathVariable("id") Integer id,
                                     @PathVariable("username") String name,
                                     @PathVariable Map<String,String> pv,
                                     @RequestHeader("User-Agent") String UserAgent,
                                     @RequestHeader Map<String,String> header){
    
        Map<String, Object> map = new HashMap<>();
        map.put("id",id);
        map.put("name",name);
        map.put("pv",pv);
        map.put("UserAgent",UserAgent);
        map.put("header",header);
        return map;
    }
    

    image-20230718094438474

  • @RequestParam获取请求参数

  • @CookieValue获取cookie值

  • @RequestAttribute获取Request域属性

  • @RequestBody获取请求体

  • @MatrixVariable矩阵变量(spring boot默认禁用掉了矩阵变量)

    /cars/{path}?xxX=xxx&aaa=ccc querystring查询字符串。@RequestParam;《br/>/cars/{path; low=34;brand=byd , audi,yd} ﹔矩阵变量

    页面开发,cookie禁用了,session里面的内容怎么使用;

    session.set( a, b)—> jsessionid —> cookie ---->每次发请求携带。url重写: /abc;jsesssionid=xxxx把cookie的值使用矩阵变量的方式进行传递

    <a href=" /cars/sell;low=34;brand=byd,audi, yd">@MatrixVariable(矩阵变量)</a>
    〈a href= "/cars/sell;low=34;brand=byd;brand=audi;brand=yd">@MatrixVariable(矩阵变量)</a>〈a href="/boss/1;age=20/2;age=10">@MatrixVariable(矩阵变量〉/boss/{[bossId}/ {empId}</a>
    

    ";“之前是路径,之后的分号隔开的是矩阵变量,”,"隔开代表这个矩阵变量有多个值

3.3、Thymeleaf语法

  • th:text 对文本转义,特殊字符也会被当作普通字符输出
  • th:utext 对文本不转义,按照你写的特殊字符解释

修改两个地方再测试,msg的内容包上h1标签,分别使用test和utext测试

@RequestMapping("/t")
    public String test(Model model){
        model.addAttribute("msg","<h1>嗨嗨嗨,Thymeleaf</h1>");
        return "test";
    }
<div th:text="${msg}"></div>
<div th:utext="${msg}"></div>

image-20230716102210904

遍历each,和vue中的for each一样的

再加一个集合

 model.addAttribute("user", Arrays.asList("张三","李四"));
<hr>
<!--遍历数组user得到一个集合use,然后使用th:text绑定去取use  ${use}-->
<h2 th:each="user:${user}" th:text="${user}"></h2>

image-20230716111229187

4、员工信息管理系统(练习)

4.1、准备工作,找静态资源

新建项目SpringBoot-04-system,添加这些依赖

image-20230718112506005

导入静态资源

image-20230718112909028

4.2、伪造数据库

部门表

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

//部门表
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Department {
    private Integer id;
    private String departmentName;
}

员工表

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 date;
}

模拟数据库中员工表的数据.

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 {
    //模拟数据库中员工表的数据
    static private Map<Integer, Employee> employees;
    @Autowired
    private DepartmentDao departmentDao;

    static {
        employees = new HashMap<>();//创建一个员工表
        employees.put(1, new Employee(1, "zsr", "1234@qq.com", 1, new Department(1, "技术部"), new Date()));
        employees.put(2, new Employee(2, "lyr", "1345@qq.com", 1, new Department(2, "市场部"), new Date()));
        employees.put(3, new Employee(3, "gcc", "5665@qq.com", 0, new Department(3, "调研部"), new Date()));
        employees.put(4, new Employee(4, "zyx", "7688@qq.com", 1, new Department(4, "后勤部"), new Date()));
        employees.put(5, new Employee(5, "zch", "8089@qq.com", 1, new Department(5, "运营部"), new Date()));
    }

    //主键自增
    private static Integer initialID = 6;

    //增加一个员工
    public void addEmployee(Employee employee) {
        if (employee.getId() == null)
            employee.setId(initialID++);
        employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
        employees.put(employee.getId(), employee);
    }

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

    //通过id查询员工
    public Employee getEmployeeByID(Integer id) {
        return employees.get(id);
    }

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

模拟部门表的dao

import org.springframework.stereotype.Repository;

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

@Repository
public class DepartmentDao {
    //模拟数据库中的数据
    private static Map<Integer, Department> departments = null;

    static {
        departments = new HashMap<>();//创建一个部门表
        departments.put(1, new Department(1, "技术部"));
        departments.put(2, new Department(2, "市场部"));
        departments.put(3, new Department(3, "调研部"));
        departments.put(4, new Department(4, "后勤部"));
        departments.put(5, new Department(5, "运营部"));
    }

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

    //通过id得到部门
    public Department getDepartmentById(int id) {
        return departments.get(id);
    }
}

处理首页index,自定义MyMVCConfig

@Configuration
public class MyMVCConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
    }
}

启动访问,可以访问index.html

4.3、将所有页面的静态资源使用thymeleaf接管

将thymeleaf的命名空间引入

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

然后修改所有的静态资源引入,链接用@{}

4.4、国际化

首先确保idea的properties编码都统一为UTF-8

image-20230719091625986

然后在resource下再建一个国际化的文件i18n,在这个目录下再新建两个个配置文件分别配置中英文

  • login.properties:默认无选择语言时生效
  • login_en_US.properties:英文生效
  • login_zh_CN.properties:中文生效

image-20230719093051052

点开login.properties可视化配置,点左上角的+号添加key,然后在右边的三个配置框中写值,第一个是默认的,第二个是英语,第三个是中文。

image-20230719093639974

登录页中还有几个属性可以直接添加,idea好像不能保存使用可视化配置的键值,所以可以直接在对应的配置文件中配一下就好了。

login_en_US.properties

login.btn=sign in
login.password=Password
login.remember=Remember me
login.tip=Please sign in
login.username=Username

login_zh_CN.properties和login.properties

login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名

配置好了,接下来就是让它生效,在application.properties中配置

#配置国家化文件的真实路径
spring.messages.basename=i18n.login

然后去index.html改这些国际化的消息,thymeleaf的语法是 #{…}

image-20230719100300224

刷新一下就有默认的效果了

image-20230719100431893

现在还不能实现点下面的中文和English就切换

先在这俩标签上加跳转链接

<!--这里传入参数不需要使用?使用key=value-->
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>

显然两个链接就需要进行处理,所以自定义地区解析器,看源码。

先搜索WebMvcAutoConfiguration找到关于地区解析器的方法localeResolver

@Bean
@ConditionalOnMissingBean(
    name = {"localeResolver"}
)
public LocaleResolver localeResolver() {
    //如果用户自己配了就用用户配好的
    if (this.webProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.WebProperties.LocaleResolver.FIXED) {
        return new FixedLocaleResolver(this.webProperties.getLocale());
    } else {
        //用户没配就使用默认的,这里它new了一个地区解析器的对象,然后使用setDefaultLocale给设置了默认的地区解析器
        AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
        localeResolver.setDefaultLocale(this.webProperties.getLocale());
        return localeResolver;
    }
}

AcceptHeaderLocaleResolver点进去可以看到它实现类LocaleResolver接口

image-20230719112520778

所以我们要自定义地区解析器也得实现它

在config中新建MyLocaleResolver类实现LocaleResolver

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)){
            //zh_CN(语言_地区),用_分割开来
            String[] split = language.split("_");
            locale = new Locale(split[0], split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

这里还需要将它添加到组件里,在MyMVCConfig配置类中添加bean,然后重启测试

//添加自定义国际化组件
@Bean
public LocaleResolver localeResolver(){
    return new MyLocaleResolver();
}

image-20230719120950011

image-20230719121013084

4.5、登录实现

先让登录时提交的表单提交到controller处理,走/user/login就登录。我们让它在登录请求时就携带参数,username和password属性,好判断登录条件。

<form class="form-signin" th:action="@{/user/login}">

新建loginController类,如果登录条件不满足,就给一个回显消息mag,然后在前端加一个p标签提示。

由于我们现在提交表单时浏览器上会直接显示用户名和密码,这就很暴露了,所以设置main.html作为dashboard的映射页,在MyMVCConfig可以给它添加一个地址映射,让真正的首页dashboard.html与mian.html对应,在loginController就直接让请求重定向到main.html

MyMVCConfig添加项

registry.addViewController("/main.html").setViewName("dashboard");

loginController

@Controller
public class loginController {
    @RequestMapping("/user/login")
    public String login(@RequestParam("username") String name,
                        @RequestParam("password") String pwd,
                        Model model){
        //如果用户名和密码都正确,用户名为:admin 密码给为123
        if ("admin".equals(name) && "123".equals(pwd)){
            //重定向到main.html页面,也就是跳到dashboard
            return "redirect:/main.html";
        }else {
            //登录有问题就设回显消息提示
            model.addAttribute("msg","用户名或密码错误!");
            return "index";//还回到登录页
        }
    }
}

测试:瞎填用户名和密码

image-20230719155736987

填正确的可以正确登录

image-20230719161134176

但是现在就算不经过登录页面也能访问到主页,所以得加登录拦截器了

4.6、登录拦截器

​ 在config下自定义拦截器LoginHandlerInterceptor,这里需要在登录时将用户登录信息放到session中,所以在此之前先判断用户有没有登录,session不为空就是登录了然后放行。如果没有登录就让它回到登录页登录,并加上错误信息“没有权限,请先登录!”,然后不放行return false。

先去loginController将用户登陆时的信息存session里

@Controller
public class loginController {
    @RequestMapping("/user/login")
    public String login(@RequestParam("username") String name,
                        @RequestParam("password") String pwd,
                        Model model, HttpSession session){
        //如果用户名和密码都正确,用户名为:admin 密码给为123
        if ("admin".equals(name) && "123".equals(pwd)){
            //重定向到main.html页面,也就是跳到dashboard
            session.setAttribute("loginname",name);
            return "redirect:/main.html";
        }else {
            //登录有问题就设回显消息提示
            model.addAttribute("msg","用户名或密码错误!");
            return "index";//还回到登录页
        }
    }
}

LoginHandlerInterceptor

public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断用户有没有登录,看session是否为空
        Object session = request.getSession().getAttribute("loginName");
        if (session == null){
            request.setAttribute("msg","没有权限,请先登录!");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else {
            return true;
        }
    }
}

然后把它注册到bean中,在MyMVCConfig中重写拦截器的方法,使用自己的,拦截的时候把静态资源放行,还要登录页的请求。

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoginHandlerInterceptor())
            .addPathPatterns("/**")//拦截所有请求
        .excludePathPatterns("/index.html","/user/login","/","/css/**","/img/**","/js/**");//除了这些
}

直接访问http://localhost:8080/main.html

image-20230719164039441

然后正常登录后再访问http://localhost:8080/main.html,由于刚才已经有了session,所以可以直接访问

image-20230719164717379

4.7、展示员工列表

点击主页的员工列表会跳转到list.html页面显示员工信息,所以需要controller处理请求/emps。

在员工列表的部分添加herf链接,作为请求/emps

list.hml也要修改这部分代码

<li class="nav-item">
    <a th:class="nav-link" th:href="@{/emps}">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
             fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
             stroke-linejoin="round" class="feather feather-users">
            <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
            <circle cx="9" cy="7" r="4"></circle>
            <path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
            <path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
        </svg>
        员工列表
    </a>
</li>

在templates下新建emp目录,用来放员工的增删改查,list.html也放这里

现在新建controller,EmployeeController处理/emps请求获取所有员工信息

由于没有server层,就直接调dao层了

@Controller
public class EmployeeController {
    @Autowired
    private EmployeeDao employeeDao;
    @RequestMapping("/emps")
    public String list(Model model){
        Collection<Employee> employees = employeeDao.getAllEmployees();
         model.addAttribute("emps",employees);
        return "emp/list";//返回list进行展示
    }

}

重启测试,点员工列表能跳到list.html页面

image-20230719181153466

因为list.html的导航栏和侧边栏都是一样的,所以为了实现组件复用,将公共部分抽取出来进行复用

在templates下新建commons包,然后新建commons.html,使用th:fragment标签将公共部分抽取出来,也就是顶部导航栏和侧边栏

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!--顶部导航栏,利用th:fragment提取出来,命名为topbar-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
    <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginName}]]</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" th:href="@{/user/logout}">log out</a>
        </li>
    </ul>
</nav>
<!--侧边栏,利用th:fragment提取出来,命名为sidebar-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="siderbar">
    <div class="sidebar-sticky">
        <ul class="nav flex-column">
            <li class="nav-item">
                <a th:class="${active=='dashboard.html'?'nav-link active':'nav-link'}" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-home">
                        <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
                        <polyline points="9 22 9 12 15 12 15 22"></polyline>
                    </svg>
                    首页 <span class="sr-only">(current)</span>
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-file">
                        <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
                        <polyline points="13 2 13 9 20 9"></polyline>
                    </svg>
                    Orders
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-shopping-cart">
                        <circle cx="9" cy="21" r="1"></circle>
                        <circle cx="20" cy="21" r="1"></circle>
                        <path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
                    </svg>
                    Products
                </a>
            </li>
            <li class="nav-item">
                <a th:class="${active=='list.html'?'nav-link active':'nav-link'}" th:href="@{/emps}">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-users">
                        <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
                        <circle cx="9" cy="7" r="4"></circle>
                        <path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
                        <path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
                    </svg>
                    员工列表
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-bar-chart-2">
                        <line x1="18" y1="20" x2="18" y2="10"></line>
                        <line x1="12" y1="20" x2="12" y2="4"></line>
                        <line x1="6" y1="20" x2="6" y2="14"></line>
                    </svg>
                    Reports
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-layers">
                        <polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
                        <polyline points="2 17 12 22 22 17"></polyline>
                        <polyline points="2 12 12 17 22 12"></polyline>
                    </svg>
                    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="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
                     stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
                     class="feather feather-plus-circle">
                    <circle cx="12" cy="12" r="10"></circle>
                    <line x1="12" y1="8" x2="12" y2="16"></line>
                    <line x1="8" y1="12" x2="16" y2="12"></line>
                </svg>
            </a>
        </h6>
        <ul class="nav flex-column mb-2">
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-file-text">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    Current month
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-file-text">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    Last quarter
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-file-text">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    Social engagement
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                         fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                         stroke-linejoin="round" class="feather feather-file-text">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    Year-end sale
                </a>
            </li>
        </ul>
    </div>
</nav>
</html>

然后dashboard.html和list.html中的导航栏和侧边栏就就可以删除了,删除是删除了,我们还得导进去,使用th:replace进行覆盖,将topbarsidebar导进去。

<!--顶部导航栏-->
<div th:replace="~{commons/commons::topbar}" }></div>

<div class="container-fluid">
    <div class="row">
        <!--侧边栏-->
        <div th:replace="~{commons/commons::siderbar(active='dashboard.html')}"></div>

导入之后就可以看到与原来一样的效果。

高亮处理

侧边栏中每一个选项在点的时候只有首页的那个选项有高亮,我们要做的是选择哪个哪个就高亮,没选择就不高亮。

能让它高亮的是class="nav-link active"属性,可以使用传递参数判断点击了哪个标签实现相应的高亮

dashboard.html的侧边栏标签传递参数activedashboard.html,同样在list.html的侧边栏标签传递参数activelist.html

<!--侧边栏-->
<div th:replace="~{commons/commons::siderbar(active='dashboard.html')}"></div>
<!--侧边栏-->
<div th:replace="~{commons/commons::siderbar(active='list.html')}"></div>

然后在commons.html公共组件中使用三元运算判断,如果点击那个选择它会携带参数active,这样在commons.html对应的标签上就可以使用thymeleaf的三元判断,如果有这个参数就是带高亮的标签,如果没有就是普通的。

image-20230719193126428image-20230709193142124然后就实现了点哪亮哪(当然这里只有这两个选项写了其他还不能高亮)

显示员工列表

修改list…html,同时添加编辑和删除俩按钮

<div class="table-responsive">
    <table class="table table-striped table-sm">
        <thead>
        <tr>
            <th>id</th>
            <th>lastName</th>
            <th>email</th>
            <th>gender</th>
            <th>department</th>
            <th>date</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="emp:${emps}">
            <td th:text="${emp.getId()}"></td>
            <td th:text="${emp.getLastName()}"></td>
            <td th:text="${emp.getEmail()}"></td>
            <td th:text="${emp.getGender()==0?'女':'男'}"></td>
            <td th:text="${emp.getDepartment().getDepartmentName()}"></td>
            <td th:text="${#dates.format(emp.getDate(),'yyyy-MM-dd HH:mm:ss')}"></td>
            <td>
                <a class="btn btn-sm btn-primary" th:href="@{/edit/{id}(id=${emp.getId()})}">编辑</a>
                <a class="btn btn-sm btn-danger" th:href="@{/delete/{id}(id=${emp.getId()})}">删除</a>
            </td>
        </tr>
        </tbody>
    </table>
</div>

image-20230719193627588

4.8、添加员工

点击按钮提交—>跳转到添加的页面—>添加员工成功返回首页

首先在list.html的显示员工列表上面添加一个“添加员工按钮”,然后href链接请求/add,这里默认的就是get方式,然后去写add的页面跳转请求,让它跳转到add.html页面。

<h2><a class="btn btn-sm btn-success" th:href="@{/add}">添加员工</a></h2>
//添加员工,跳转到添加员工页,并将所有的职位信息放到视图模型中,在add.html页面显示出来选择列表
@GetMapping("/add")
public String toAddPage(Model model){
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "emp/add";
}

add.html是复制list的,做了一些修改,这里表单提交时设置它的method=“post”,请求的还是/add,但是请求的方式不一样,所以需要再写一个controller处理,把从表单拿到的要添加的对象调用dao的save方法保存,最后重定向到展示所有员工请求。

<!DOCTYPE html>
<!-- saved from url=(0052)http://getbootstrap.com/docs/4.0/examples/dashboard/ -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta http-equiv="Content-Type" content="text/html; 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="">

    <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">
    <style type="text/css">
        /* Chart.js */

        @-webkit-keyframes chartjs-render-animation {
            from {
                opacity: 0.99
            }
            to {
                opacity: 1
            }
        }

        @keyframes chartjs-render-animation {
            from {
                opacity: 0.99
            }
            to {
                opacity: 1
            }
        }

        .chartjs-render-monitor {
            -webkit-animation: chartjs-render-animation 0.001s;
            animation: chartjs-render-animation 0.001s;
        }
    </style>
</head>

<body>
<!--顶部导航栏-->
<div th:replace="~{commons/commons::topbar}" }></div>

<div class="container-fluid">
    <div class="row">
        <!--侧边栏-->
        <div th:replace="~{commons/commons::siderbar(active='list.html')}"></div>


        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/add}" method="post">
                <div class="form-group">
                    <label>LastName</label>
                    <input type="text" name="lastName" class="form-control" placeholder="lastname:zsr">
                </div>
                <div class="form-group">
                    <label>Email</label>
                    <input type="email" name="email" class="form-control" placeholder="email:xxxxx@qq.com">
                </div>
                <div class="form-group">
                    <label>Gender</label><br/>
                    <div class="form-check form-check-inline">
                        <input class="form-check-input" type="radio" name="gender" value="1">
                        <label class="form-check-label"></label>
                    </div>
                    <div class="form-check form-check-inline">
                        <input class="form-check-input" type="radio" name="gender" value="0">
                        <label class="form-check-label"></label>
                    </div>
                </div>
                <div class="form-group">
                    <label>department</label>
                    <!--注意这里的name是department.id,因为传入的参数为id-->
                    <select class="form-control" name="department.id">
                        <option th:each="department:${departments}" th:text="${department.getDepartmentName()}"
                                th:value="${department.getId()}">
                        </option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Birth</label>
                    <!--springboot默认的日期格式为yy/MM/dd-->
                    <input type="text" name="date" class="form-control" placeholder="birth:yyyy/MM/dd">
                </div>
                <button type="submit" class="btn btn-primary">添加</button>
            </form>
        </main>
    </div>
</div>


可以下拉列表选择部门,这里它的name属性是department的id属性,不能是对象,因为传入的参数就是id

image-20230720110315769

随便添加一个

image-20230720110930054日期格式默认为

image-20230720110947076

可以看到已经添加过来了。

日期格式默认为yyyy/MM/dd,我们也可以改成yyyy-MM-dd的格式,到配置文件application.properties中设置就行,但改完就不能使用yyyy/MM/dd格式了。

#更改日期格式
spring.mvc.format.date=yyyy-MM-dd

更改配置文件,需要重启

image-20230720111426120

image-20230720111819759

一次运行,随便添加都可以,重启后就会清空,因为没有数据库。

4.9、修改

之前的编辑按钮现在改成a链接,请求路径需要加上当前员工的id属性,th:href=“@{/edit/{id}(id=${emp.getId()})}”

<a class="btn btn-sm btn-primary" th:href="@{/edit/{id}(id=${emp.getId()})}">编辑</a>

然后写跳转到编辑页的controller,edit

//跳转到修改页面,同时将要修改的员工信息也放到视图模型,还有所有的职位信息
@RequestMapping("/edit/{id}")
public String edit(@PathVariable("id") int id,Model model){
    //通过id找到这个员工,并放到视图模型
    Employee employee = employeeDao.getEmployeeByID(id);
    model.addAttribute("employee",employee);
    //和添加员工一样,为了那个选择列表
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "emp/edit";
}

复制一份add.html为edit.html修改内容,每一个input都加上th:value然后employee.getxxx把这个员工的值拿出来,做默认的,select选择列表设置默认选择项th:selected,设为员工本来的,th:selected=“${department.getId()==employee.department.getId()}”

<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
    <form th:action="@{/edit}" method="post">
        <!--隐藏域,将这个员工的id也提交,保存的时候就是修改,不然一直都是保存添加新的-->
        <input type="hidden" name="id" th:value="${employee.getId()}">
        <div class="form-group">
            <label>LastName</label>
            <input th:value="${employee.getLastName()}" type="text" name="lastName" class="form-control"
                   placeholder="lastname:zsr">
        </div>
        <div class="form-group">
            <label>Email</label>
            <input th:value="${employee.getEmail()}" type="email" name="email" class="form-control"
                   placeholder="email:xxxxx@qq.com">
        </div>
        <div class="form-group">
            <label>Gender</label><br/>
            <div class="form-check form-check-inline">
                <input th:checked="${employee.getGender()==1}" class="form-check-input" type="radio"
                       name="gender" value="1">
                <label class="form-check-label"></label>
            </div>
            <div class="form-check form-check-inline">
                <input th:checked="${employee.getGender()==0}" class="form-check-input" type="radio"
                       name="gender" value="0">
                <label class="form-check-label"></label>
            </div>
        </div>
        <div class="form-group">
            <label>department</label>
            <!--注意这里的name是department.id,因为传入的参数为id-->
            <select class="form-control" name="department.id">
                <option th:selected="${department.getId()==employee.department.getId()}"
                        th:each="department:${departments}" th:text="${department.getDepartmentName()}"
                        th:value="${department.getId()}">
                </option>
            </select>
        </div>
        <div class="form-group">
            <label>Birth</label>
            <!--springboot默认的日期格式为yy/MM/dd-->
            <input th:value="${#dates.format(employee.getDate(),'yyyy/MM/dd')}" type="text" name="date"
                   class="form-control"
                   placeholder="birth:yy/MM/dd">
        </div>
        <button type="submit" class="btn btn-primary">修改</button>
    </form>
</main>

编写修改的controller,update

//修改
@PostMapping("/edit")
public String update(Employee employee){
    employeeDao.addEmployee(employee);
    return "redirect:/emps";
}

现在编辑张三

image-20230720155311164

在这里插入图片描述
原始据image-20230720155423798修改后,由于日期格式改了,所以直接用改之后的image-20240720155522401

可以看到已经改好了。

4.10、删除、404处理和注销

删除就一个删除的请求/delete带上id,controller调用删除就行了

<a class="btn btn-sm btn-danger" th:href="@{/delete/{id}(id=${emp.getId()})}">删除</a>

deleteEmp

//删除
@RequestMapping("/delete/{id}")
public String deleteEmp(@PathVariable("id") int id){
    employeeDao.deleteEmployeeByID(id);
    return "redirect:/emps";
}

没删之前,现在全删除

image-20230720160328958

image-20230720160345314删没了,重启一下就行了,反正没有数据库本身就不是永久存储。

现在搞404页面,spring boot的404只需要在templates中建一个error文件夹,然后404就是404.html,500就是500.html就好了。

image-20230720160741565

随便瞎访问

image-20230720161243073

注销

把session移除就好了,在公共部分commons里,导航栏那里的注销添加请求/user/logout,写controllor把session移除就行,再给它重定向到首页,controller写loginController里。

//注销
@RequestMapping("/user/logout")
public String logout(HttpSession session) {
    session.invalidate();
    return "redirect:/main.html";
}

点注销后直接出来,让登录

image-20231720162611961

image-20230720162530282

至此,小练习结束。

5、整合JDBC

5.1、测试

新建项目springboot-05-jdbc,选择依赖的时候把JDBC API和MySQL Driver选上。

然后就能看到它自动导入的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
 <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
</dependency>

然后新建一个配置文件application.yml,在这里配置数据库的数据源。

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf-8
    
    #serverTimezone=Asia/Shanghai是时区,上海

springboot的自动装配机制会自动生成相应的对象。

测试:查看一下默认的数据源,获得数据库连接,关闭连接

class SpringBoot05JdbcApplicationTests {
    @Autowired(required = false)
    DataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        //获取默认数据源
        System.out.println(dataSource.getClass());

        //获取连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        //关闭连接
        connection.close();
    }

}

默认的数据源:class com.zaxxer.hikari.HikariDataSource

输出的连接:HikariProxyConnection@1761495255 wrapping com.mysql.cj.jdbc.ConnectionImpl@379ce046

image-20230721095747977

spring boot已经配置了很多的模板,XXXTemplate,可以直接拿来用

测试:先导一下web的依赖,然后写一个JDBCController,使用JdbcTemplate将数据库的表查询出来并访问得到。

@RestController
public class JDBCController {
    @Autowired(required = false)
    JdbcTemplate jdbcTemplate;
    @RequestMapping("/list")
    public List<Map<String,Object>> userList(){
        String sql = "select * from mybatis.user";
        return jdbcTemplate.queryForList(sql);
    }
}

image-20230721102113126可以正常查出来

接下来就是增删改操作了

增:

@RequestMapping("/add")
public String add(){
    String sql ="insert into mybatis.user() values(8,'王小明','666666')";
    jdbcTemplate.update(sql);
    return "添加成功";
}

image-20230721104827805添加成功,去数据库查看是否添加到库里

image-20230721104918259确实添加成功

改:刚才添加的id是8,现在修改也是8

@RequestMapping("/update/{id}")
public String update(@PathVariable("id") int id){
    String sql ="update mybatis.user set name=?,pwd=? where id="+id;
    Object[] o = new Object[2];
    o[0] = "wangxiaoming";
    o[1] = "abcdefghijk";
    jdbcTemplate.update(sql,o);
    return "修改成功";
}

image-20230721105102495

image-20230721105130060

删:删除8号

@RequestMapping("/delete/{id}")
public String delete(@PathVariable("id") int id){
    String sql = "delete from mybatis.user where id=?";
    jdbcTemplate.update(sql,id);
    return "删除成功";
}

image-20230721105228585

image-20230721105244384

5.2、整合Druid数据源

Druid为监控而生的数据库连接池,它是阿里巴巴开源平台上的一个项目。Druid是Java语言中最好的数据库连接池,Druid能够提供强大的监控和扩展功能.它可以替换DBCP和C3P0连接池。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。

导入依赖

<!--Druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>


配置文件中配置数据库的数据源类型:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf-8
    type: com.alibaba.druid.pool.DruidDataSource

各配置说明

后台监控功能实现

在application.yml中设置一些参数

#Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

然后编写配置类,在config包中新建DruidConfig

@Configuration
public class DruidConfig {

    //使用私有属性,绑定配置文件
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource(){
        return new DruidDataSource();
    }

    //后台监控,web.xml  ServletRegistrationBean
    //因为spring boot内置了servlet容器,所以没有web.xml,想代替就使用ServletRegistrationBean
    @Bean
    public ServletRegistrationBean setViewServlet(){
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        //后台需要登录,设置账号密码
        HashMap<String, String> initParameters = new HashMap<>();
        //登录时的key是固定的不要变
        initParameters.put("loginUsername","admin");
        initParameters.put("loginPassword","123456");
        //设置允许谁可以访问,空的就是谁都允许
        initParameters.put("allow","");

        //设置初始化参数
        bean.setInitParameters(initParameters);
        return bean;
    }

启动程序访问http://localhost:8080/druid/进入监控后台

image-20230721154224764

image-20230721154310701

现在执行之前的SQL就可以看到执行的详细信息了

image-20230721160707488

image-20230721160743502

6、整合MyBatis

meven官网找到依赖

<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>
        
<!--顺便导个lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

  1. 再新建项目spring boot-06-mybatis,jdbc时选的依赖还选上

  2. 连上数据库,再导入依赖,把lombok也顺便导了。

  3. 配置数据源application.yml

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: 123456
        url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf-8
    

测试连接是否正常

@SpringBootTest
class SpringBoot06MybatisApplicationTests {
    @Autowired(required = false)
    DataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        System.out.println(dataSource.getClass());
        System.out.println(dataSource.getConnection());
    }

}

image-20230721163423880可以正常连接

6.1、编写实体pojo

新建包pojo,写user表的实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

6.2、Mapper接口

新建mapper包,新建UserMapper接口,打上@Mapper注解表明了这是mybatis的mapper类

这里写增删改查的方法:

import com.zm.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
    //查询所有
    List<User>  queryList();
    //根据id查询
    User queryById(int id);
    //增加
    int add(User user);
    //修改
    int update(User user);
    //删除
    int delete(int id);
}

6.3、UserMapper.xml

在resources下建mybatis.mapper,新建UserMapper.xml,在这里写sql

image-20230721165820345

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zm.mapper.UserMapper">
    <select id="queryList" resultType="User">
        select * from mybatis.user;
    </select>
    <select id="queryById" resultType="User">
        select * from mybatis.user where id = #{id};
    </select>
    <insert id="add" parameterType="User">
        insert into mybatis.user(id, name, pwd) VALUES (#{id},#{name},#{pwd});
    </insert>
    <update id="update" parameterType="User">
        update mybatis.user set name =#{name},pwd=#{pwd} where id=#{id};
    </update>
    <delete id="delete" parameterType="int">
        delete from mybatis.user where id=#{id};
    </delete>
</mapper>

6.4、配置文件整合mybatis

#整合mybatis
mybatis:
  type-aliases-package: com.zm.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml

6.5、编写UserController

@RestController
public class UserController {
    @Autowired
    UserMapper userMapper;

    //查询所有
    @RequestMapping("/query")
    public List<User> query(){
        return userMapper.queryList();
    }
    //根据id查询
    @RequestMapping("/query/{id}")
    public User queryById(@PathVariable("id") int id){
        return userMapper.queryById(id);
    }
    //添加
    @RequestMapping("/add")
    public String add(){
       int i = userMapper.add(new User(11,"哈喽","000000"));
        if (i>0){
            return "添加成功";
        }else {
            return "添加失败";
        }
    }
    //修改
    @RequestMapping("/update")
    public String update(){
        int i = userMapper.update(new User(11,"哈喽02","1110"));
        if (i>0){
            return "修改成功";
        }else {
            return "修改失败";
        }
    }
    //删除
    @RequestMapping("/delete/{id}")
    public String delete(@PathVariable("id") int id){
        userMapper.delete(id);
        return "删除成功";
    }
}

查询所有:

image-20230721175925899

查询id为6的人:

image-20230721180032099

增加一个人:

image-20230721180058251[外链图片转在这里插入图片描述

再修改他:

image-20230721180150452image-20230721180203976

再删除他

image-20230723095134953image-20230721180256446

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当前课程中博客项目的实战源码是我在 GitHub上开源项目 My-Blog,目前已有 3000 多个 star:本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 大部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 个人博客项目功能的讲解,通过本课程的学习,不仅仅让你掌握基本的 Spring Boot 开发能力以及 Spring Boot 项目的大部分开发使用场景,同时帮你提前甄别和处理掉将要遇到的技术难点,认真学完这个课程后,你将会对 Spring Boot 有更加深入而全面的了解,同时你也会得到一个大家都在使用的博客系统源码,你可以根据自己的需求和想法进行改造,也可以直接使用它来作为自己的个人网站,这个课程一定会给你带来巨大的收获。作者寄语本课程录制于 2020 年,代码基于 Spring Boot 2.x 版本。到目前为止,Spring Boot 技术栈也有一些版本升级,比如 Spring Boot 2.7 发版、Spring Boot 3.x 版本发布正式版本。对于这些情况,笔者会在本课程实战项目的开源仓库中创建不同的代码分支,保持实战项目的源码更新,保证读者朋友们不会学习过气的知识点。课程特色 课程内容紧贴 Spring Boot 技术栈,涵盖大部分 Spring Boot 使用场景。开发教程详细完整、文档资源齐全、实验过程循序渐进简单明了。实践项目页面美观且实用,交互效果完美。包含从零搭建项目、以及完整的后台管理系统和博客展示系统两个系统的功能开发流程。技术栈新颖且知识点丰富,学习后可以提升大家对于知识的理解和掌握,对于提升你的市场竞争力有一定的帮助。实战项目预览    

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fiercezm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值