SpringBoot学习笔记

本文为狂神说SpringBoot教程学习笔记 狂神说-JavaSpringBoot教程IDEA版

第一个springboot程序

  • 在IDEA中创建springboot工程

  • 目录:在同级目录下建包

    image-20210418092443455

  • controller包中的hellocontroller:

    通过完成配置可以实现在网页中使用地址访问内容

    在pom.xml中添加spring-boot-starter-web依赖即可实现web功能,其中内嵌了tomcat

    package com.jinfz.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    //改变代码之后需要重启项目
    
    //下方代码,因为有两层的mapping,所以在网址中需要输入/hello/hello
    
    @Controller
    @RequestMapping("/hello")
    public class hellocontroller {
    
        @GetMapping("/hello")
        @ResponseBody
        public String hello(){
            //调用业务,接收前端参数!
            return "hello";
        }
    }
    

    image-20210418104541760

  • 在resources–properties中更改配置

    更改项目端口号:

    #更改项目端口号
    server.port=8081
    

    如果使用yml配置文件,则会有对应格式,在下文中有讲解

  • 在resources中创建banner.txt,可以更改编译中展示的横幅:

    image-20210418104821394

原理初探(?)

自动配置:

pom.xml

  • spring-boot-dependencies:核心依赖在父工程中(…)
  • 我们在写或者引入一些springboot依赖的时候,不需要指定版本,就因为有这些版本仓库

启动器start

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
  • springboot的启动场景
  • 比如spring-boot-stater-web:自动导入web环境的所有依赖
  • spring将一个个的功能场景变成启动器
  • 要实现什么功能,只需要找到对应的启动器start(即在pom.xml中导入依赖,然后重新加载maven依赖,有时候可能还需要重启项目才能生效)
//@SpringBootApplication:标注这个类是一个springboot的应用
@SpringBootApplication
public class Springboot01HelloworldApplication {
    public static void main(String[] args) {
        //将springboot这个应用启动
        //反射加载上面的类的对象,以实现功能
        SpringApplication.run(Springboot01HelloworldApplication.class, args);
    }
}

@SpringBootApplication是个组合注解,其内包含以下内容:

@ComponentScan //扫描下列的包,可以剔除哪些东西

@SpringBootConfiguration(配置)

@Configuration
	@Component
//点进去两层,发现其只是spring的一个组件

@EnableAutoConfiguration(自动配置)

@AutoConfigurationPackage//自动配置包
	@Import({Registrar.class})//自动配置 `包注册`
@Import({AutoConfigurationImportSelector.class}) //自动配置 导入选择器(import selector)

//获取所有的配置(获取候选的配置:核心方法)
 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

获取候选的配置

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

image-20210418114133383

**结论:**spring中所有的自动配置都在启动类中扫描并加载–spring.factories,但不一定生效。要判断条件是否成立,只要导入了对应的starter,就有对应的启动器,然后自动装配就会生效,然后就配置成功了。

  1. springboot启动时,从类路径下/META-INF/spring.factories中获取指定的值
  2. 将这些自动配置的类导入容器,自动配置就会生效,帮我们进行自动配置
  3. 以前需要手动配置的东西,spring帮我们做了
  4. 整个javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.4.5.RELEASE.jar这个包下
  5. 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
  6. 容器中也会存在很多的xxxxAutoconfigure 文件,这些类会给容器中导入这个场景所需要的所有组件

关于springboot

  • 自动装配
  • run()
    • 判断普通项目还是web项目
    • 推断当前的主类
    • 。。。

全面接管springmvc配置

SpingBoot配置

对比yaml、properties

yaml语法讲解

application.properties

  • 语法结构:key=value

application.yml

  • 语法结构:key : 空格 value
  • 注意要有空格(对于空格的要求极其严格)

修改springboot的默认配置

yaml中可以配置很多东西(随机值,默认值,判断是否存在)

yaml可以直接给实体类赋值(统一赋值)(严格要求空格)application.yml

person:
  name: qinjiang
  age: 12
  happy: true
  maps: {k1: v1,k2: v2}
  list:
    -code
    -music
    -girls
  dogs:
    name: wangcai
    age: 3

person.java中绑定指定的加载:

@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private  Integer age;
    private Boolean happy;
    private Data birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

    public Person() {
    }

    public Person(String name, Integer age, Boolean happy, Data 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 Integer getAge() {
        return age;
    }

    public Boolean getHappy() {
        return happy;
    }

    public Data getBirth() {
        return birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public List<Object> getLists() {
        return lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setHappy(Boolean happy) {
        this.happy = happy;
    }

    public void setBirth(Data birth) {
        this.birth = birth;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public void setLists(List<Object> lists) {
        this.lists = lists;
    }

    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 +
                '}';
    }
}
@ConfigurationProperties@Value
功能批量诸如配置文件中的属性
松散绑定支持
SpEL不支持
JSR303数据校验支持
复杂类型封装支持

jsr303数据格式校验

jsr303数据校验

(其中的几种用法)

image-20210419100804714

javaconfig:在其中可以设置全局(?)

image-20210419090555395

对于不同的配置版本,可以设置为dev、test环境【多环境下切换:实际开发中会用到多个环境】

yaml:

server:
  port: 8082
spring:
  config:
    activate:
      on-profile: dev

properties: 设置不同的文件名

applicatin-dev.properties 表示开发环境

applicatin-test.properties表示测试环境

SpringBoot Web开发

静态资源处理

spring boot项目中没有传统的webapp,因此有了替代项。

要解决的问题:

  • 导入 静态资源(html、css)【在resources/static/、resources/public/、resources/templates/】
  • 首页 :localhost:8080/hello
  • jsp,模板引擎 Thymeleaf
  • 装配拓展SpringMVC(文件上传,json)
  • 增删改查
  • 拦截器
  • 国际化(中英文切换)

导入web资源的方法:

  1. webjars网站:可以通过maven的方式引入

  2. 静态资源目录:

  • classpath:/**(该目录下的所有内容均可访问)【使用时直接在后方地址填写需要访问的文件名】

  • classpath:/resources/【优先级较高】【存放upload上传的文件】

  • classpath:/static/【优先级其次】【存放静态资源:图片。。】

  • classpath:/public/【优先级最后】【存放公共资源】

**总结:**在springboot,可以使用以下方式处理静态资源

  • webjars localhost:8080/webjars/

  • public, static, /**, resources,

  • 静态资源目录优先级

首页定制

创建index.html文件,将其放在resources下的三个文件夹中的任意一个,如然后直接访问localhost:8080

  • 可以在properties文件中配置

    server.servlet.=/kuang 
    //实现对于网址的拓展,使访问localhost:8080不再能直接访问主页,需要添加/kuang
    
  • 如果使用thymeleaf引擎托管,需要做如下设置:

    • 手动加入命名空间xmlns:th="http://www.thymeleaf.org"

    • 在本地url地址前,需要进行如下修改:

      <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
      //在href前添加th:,并将本地url地址用@{}包裹
      

Thymeleaf模板引擎

可以在controller中进行页面跳转,访问template中的文件

结论:需要使用Thymeleaf,只需要导入对应的依赖就可以了。(注意:版本应为3.0.x及以上)

Thymeleaf使用文档

MVC配置原理及扩展SpringMVC

自定义一个视图解析器:

//如果想要自定义一些定制化的功能,只需要写这个组件,只需要将它交给spring boot,会帮我们自动装配
//拓展springmvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    //ViewResolver实现了视图解析器接口的类,我们就可以把它看做视图解析器

    //自定义了一个自己的视图解析器
    @Bean
    public ViewResolver myViewResolver(){
        return new MyViewResolver();
    }

    public static class MyViewResolver implements ViewResolver{
        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }
}

视图跳转:

//如果要扩展springmvc,官方推荐使用下列方法:@Configuration
@Configuration
//@EnableWebMvc 会导入一个类:DelegatingWebMvcConfiguration:从容器中获取所有的webmvcconfig
//该注解不能写,会使自动配置失效
public class MyMvcConfig implements WebMvcConfigurer {
    //视图跳转
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/kuang").setViewName("test");
    }
}

在springboot中,有非常多的xxx Configuration帮助我们进行扩展配置,在源码中需要注意它帮我们配置了哪些功能。

后端部分

数据库构建(伪造)

后续通过mysql创建数据库

  1. 在pojo中创建对象 员工部门

    //员工表
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    
    public class Employee {
        private Integer id;
        private String lastName;
        private String email;
        private Integer gender;//0表示女,1代表男
        private Department department;
        //注意导入utils下的Date,如果导入sql下的date会报错。
    
    }
    

    注意事项:

    1.使用@Data需要先导入lombok依赖 lombok中的@Data注解

    2.使用@NoArgsConstructor、@AllArgsConstructor,引入无参构造、有参构造

    //部门表
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    //有参、无参构造
    public class Department {
        private Integer id;
        private String departmentName;
    }
    
  2. 在dao中创建EmployeeDaoDepartmentDao

    //员工DAO
    @Repository
    public class EmployeeDao {
        //模拟数据
        public static Map<Integer, Employee> employees=null;
        //员工有所属的部门
        @Autowired
        private DepartmentDao departmentDao;
        static{
            employees=new HashMap<Integer,Employee>();//创建一个部门表
    
            employees.put(1005,new Employee(1005, "123","123@qq.com", 1, new Department(101, "教学部")));
            employees.put(1004,new Employee(1004, "123","123@qq.com", 1, new Department(101, "体育部")));
            employees.put(1003,new Employee(1003, "123","123@qq.com", 1, new Department(101, "调研部")));
            employees.put(1002,new Employee(1002, "123","123@qq.com", 1, new Department(101, "后勤部")));
            employees.put(1001,new Employee(1001, "123","123@qq.com", 1, new Department(101, "运营部")));
        }
        
        //操作如下(实现增删改查的功能):
        //主键自增
        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);
            //通过上述方法获取id,并将id给到emploee[部门关联外键]
        }
    
        //查询全部员工信息
        public Collection<Employee> getAll(){
            return employees.values();
        }
    
        //通过id查询员工
        public Employee getEmployeeById(Integer id){
            return employees.get(id);
        }
    
        //删除员工
        public void delete(Integer id){
            employees.remove(id);
        }
    }
    

    注:这两部分不懂写法

    //部门dao
    @Repository
    //让该类被spring 托管
    public class DepartmentDao {
        //初始化数据,模拟数据库
        public static Map<Integer, Department> departments=null;
    
        static{
            departments=new HashMap<Integer,Department>();//创建一个部门表
    
            departments.put(105,new Department(105, "教学部"));
            departments.put(104,new Department(104, "体育部"));
            departments.put(103,new Department(103, "调研部"));
            departments.put(102,new Department(102, "后勤部"));
            departments.put(101,new Department(101, "运营部"));
        }
        
        //获得所有部门信息
        public Collection<Department> getDepartments(){
            return departments.values();
        }
    
        //通过id得到部门
        public Department getDepartmentById(Integer id){
            return departments.get(id);
        }
    }
    

首页实现:

首页配置:注意,所有页面的静态资源都需要用thymeleaf接管;@{}

页面国际化

(切换页面语言)

(此处为可实现功能。在Thymeleaf引擎中,多处修改index.html等文件,很复杂。使用vue应该比较简单,故跳过。)

登录功能实现

在index.html中对输入内容进行提取:

<input type="text" name="username" class="form-control" placeholder="Username" required="" autofocus="">
<input type="password" name="password" class="form-control" placeholder="Password" required="">

编写loginController.java,实现具体的业务(判断用户名密码是否正确):

@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";
        }
    }
}

以上代码运行时,当用户名或密码发生错误时不会显示提示信息,需要在index.html中添加:

<!--消息回显,并且在其中根据条件给出提示信息-->
<!--此处为thymeleaf中一段高级代码,只有当msg不为空才会显示-->
<p style="color:red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

注:位置放于页面中哪一段?对应代码位置。

自定义URL

image-20210421151453964

解决办法:

需要在MyMvcConfig中增加一层映射关系

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

同时修改loginCotroller.java

if(!StringUtils.isEmpty(username) && "123456".equals(password)){
    return "redirect:/main.html";

登录拦截器

截止到目前,在未登录的情况下也能访问localhost:8080/main.html,因此设置拦截器

  • 在config文件夹下创建LoginHandlerInterceptor.java

    public class LoginHandlerInterceptor 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;
            }
        }
    }
    
  • 注意修改loginController.java

    @Controller
    public class loginController {
        @RequestMapping("/user/login")
        public String login(
                @RequestParam("username") String username,
                @RequestParam("password") String password,
                Model model,
            	//此处增加了一个输入值session
                HttpSession session){
    
            if(!StringUtils.isEmpty(username) && "123456".equals(password)){
                //此处设置session的值
                session.setAttribute("loginUser", username);
                return "redirect:/main.html";
            }else{
                model.addAttribute("msg", "用户名或密码错误!");
                return "index";
            }
        }
    }
    
  • 在MyMvcConfig中配置拦截器

    //利用重写方法配置拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginHandlerInterceptor())
            .addPathPatterns("/**")//此处拦截所有请求            			.excludePathPatterns("/index.html","/","/user/login","/css/**","/js/**","/img/**");
        //此处将登录所必须的页面及页面元素进行的排除,保证能够正常访问
    }
    

    小功能:修改dashboard.html中的company name,即可完成下图中的展示:

    <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a>
    <!--将原先的company name改为[[${session.loginUser}]]-->
    

    image-20210421154414126

员工管理系统

展示员工列表

狂神笔记:

员工列表展示

  1. 提取公共页面(fragment,insert/replace)
    1. th:fragment=“sidebar”
    2. th:replace="~{commons/commons::topbar}"
    3. 如果需要传递参数,可以直接使用()传参,接收判断即可!
  2. 列表循环展示(查询。此处为前端内容)
  3. 添加员工信息
  4. 修改员工信息
  5. 删除以及404处理

需要实现的功能:在dashboard中点击员工管理的项目,可以跳转到list.html中的对应部分

  • 创建EmployeeController.java

    先行步骤,将employee的所有查询结果都放入/emps路径下【此时,需要在resources目录下创建emps目录,并将list.html放入其中,方便管理?】

    @Controller
    public class EmployeeController {
        //本来应该调用service层,但没写service,所以此处直接调用DAO层
    
        @Autowired
        EmployeeDao employeeDao;
        //DAO层中应该是将方法写死了,所以此处直接调用
    
        //Model model的作用是将其返回给前端!!!
        @RequestMapping("/emps")
        public String list(Model model){
            Collection<Employee> employees = employeeDao.getAll();
            model.addAttribute("emps", employees);
            return "/emp/list";
        }
    }
    
  • 修改dashboard中的custom部分,将其标题栏变为中文显示,并将跳转地址变为本地查询地址

    <li class="nav-item">
        <a class="nav-link" th:href="@{/emps}">
            员工管理
        </a>
    </li>
    
  • 同时修改list.html,保证点击跳转后的页面保持一致。代码与上相同。

本课程中,该部分还对以下前端内容进行了实现:

​ 对于页面中功能条栏点击跳转后高亮的功能进行了实现;

​ 将各页面中公共的部分的代码抽取至commons.html,并在各页面中使用这些fragment;

可以在resources中配置一个commons.html,将页面中公共的部分抽取,实现代码复用。(类似于组件化?)

本课程中,这一部分在Thymeleaf引擎下进行讲解,复杂,故跳过。

记住功能和思想即可。

查询员工信息(即在点击员工管理时显示原定数据库中所有员工的信息):

  • 修改list.html中的部分代码:

    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
        <h2>Section title</h2>
        <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>birth</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()}"></td>
                        <td th:text="${emp.department.getDepartmentName()}"></td>
                        <td>
                            <!--此处为操作按钮的编写-->
                            <button class="btn btn-sm btn-primary">编辑</button>
                            <button class="btn btn-sm btn-danger">删除</button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </main>
    

添加员工信息

如何编写一个网站

  1. 前端设计构思:页面样式;数据
  2. 设计数据库(数据库设计难点!)
  3. 前端让它能够自动运行,独立化工程
  4. 数据接口如何对接:json,对象all in one
  5. 前后端联调测试
  • 有一套自己熟悉的后台模板:工作必要 x-admin

  • 前端界面:至少能通过前端框架组合出一个网站页面

    • index
    • about
    • blog
    • post
    • user
  • 让这个网站独立运行!(一个月)

SpringData

数据库连接

整合JDBC使用

  1. 创建新项目,在起始页添加 SpringWeb、JDBC API、MySQL Driver依赖

  2. 配置application.yml文件,同时连接数据库

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

    image-20210421213017059

    image-20210421213044922

    image-20210421213142421

    image-20210421213217794

  3. 编写JDBCController.java启动类,编写增删改查业务:

    @RestController
    public class JDBCController {
        @Autowired
        JdbcTemplate jdbcTemplate;
    
        //查询数据库的所有信息
        @GetMapping("/userList")
        public List<Map<String, java.lang.Object>> userList(){
            String sql="select * from user";
            List<Map<String, java.lang.Object>> list_maps = jdbcTemplate.queryForList(sql);
            return list_maps;
        }
    
        //增删改(查):
        //增:
        @GetMapping("/addUser")
        public String addUser(){
            String sql="insert into mybatis.user(id,name,pwd) values(3,'liuxi','bbaaaaaaa')";
            jdbcTemplate.update(sql);
            return "add-ok";
        }
    
        //改:
        @RequestMapping("/updateUser/{id}")
        public String updateUser(@PathVariable("id") int id){
            String sql="update mybatis.user set name=?,pwd=? where id="+id;
    
            Object[] objects=new Object[2];
            objects[0]="121212";
            objects[1]="zzzzzz";
            jdbcTemplate.update(sql,objects);
            return "update-ok";
        }
    
        //删:
        @RequestMapping("/deleteUser/{id}")
        public String deleteUser(@PathVariable("id") int id){
            String sql="delete from mybatis.user where id=?";
            jdbcTemplate.update(sql,id);
            return "delete-ok";
        }
    
    }
    

整合Druid数据源

阿里巴巴开源平台,自带监控平台、日志。

对于不同的数据源,有什么区别?

数据库的底层永远是JDBC。

Druid实现后台监控功能

  • 编写DruidConfig.java配置类

    @Configuration
    public class DruidConfig(){
        @ConfigurationProperties(prefix="spring.datasourse")
        @Bean
        public DataSource(){
            return new DruidDataSource();
        }
        
        //后台监控,相当于web.xml
        //因为SpringBoot内置了servlet容器,所以没有
        @Bean
        public ServletRegistrationBean statViewServlet(){
            ServletRegistrationBean<StatViewServlet> bean =
            new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");
            
            //后台需要有人登录,账号密码配置
            HashMap<String,String> initParameters = new HashMap<>();
            //增加配置
            initParmeters.put("loginUsername","admin");//登录key是固定的
            initParmeters.put("loginPassword","123456");
            
            //允许谁能访问
            initParameters.put("allow","");//如果为空,则所有人都能访问;可以写某个人
            
            //禁止谁能访问  initParameters.put("kuangshen","192.168.11.123");//用户名+ip
            
            
            bean.setInitParameters();//设置初始化参数
            
            return bean;
        }
        
        //filter 过滤器
        public FilterRegistrationBean webStatFilter(){
            new FilterRegistrationBean().var;
            bean.setFilter(new WebStatFilter());   
            //可以过滤哪些请求
            Map<String,String> initParameters =new HashMAp<>();
            //这些东西不进行统计
            initParameters.put("exclusions","*.js,*.css,/druid/*");
            bean.setInitParameters();        
        }
    }
    

整合Mybatis框架

整合包 mybatis-spring-boot-starter

该部分为重点

  1. 新建项目,导入web、JDBC、mysql依赖;手动导入mybatis-spring-boot-starter依赖

  2. 配置application.yml,连接数据库

    spring:
      datasource:
        username: root
        password: mysql883721@
        url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
        driver-class-name: com.mysql.cj.jdbc.Driver
    
  3. 在pojo中编写User.java,定义数据格式

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
  4. 编写接口类UserMapper.interface【不清楚该部分的作用】

    @Mapper
    @Repository
    public interface UserMapper {
    
        List<User> queryUserList();
        
        User queryUserById(int id);
        int addUser(User user);
        int updateUser(User user);
        int deleteUser(int id);
    }
    

    对于此处的@Mapper,存在另外一种解决方案:【在启动类中添加注解@MapperScan()】

    @SpringBootApplication
    @MapperScan("com.jinfz,mapper")
    public class Springboot05MybatisApplication {
     public static void main(String[] args) {       
         SpringApplication
                 .run(Springboot05MybatisApplication.class, args);
     }
    }
    
  5. 编写控制类UserController.java

    @RestController
    public class UseController {
        @Autowired
        private UserMapper userMapper;
        @GetMapping("/queryUserList")
        public List<User> queryUserList(){
            List<User> userList = userMapper.queryUserList();
            for(User user:userList){
                System.out.println(user);
            }
            return userList;
        }
    }
    
  6. application.yml中添加配置,整合mybatis

    #整合mybatis
    mybatis:
      type-aliases-package: com.jinfz.pojo
      mapper-locations: classpath:mybatis/mapper/*.xml
    
  7. 创建目录resouces–mybatis–mapper,并添加UserMapper.xml文件

    【代码样式从官网导入】mybatis官方文档

    需要手动写SQL语句:

    <?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.jinfz.mapper.UserMapper">
        <select id="queryUserList" resultType="User">
            select * from user
        </select>
    
        <insert id="addUser" parameterType="User">
            insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
        </insert>
    
        <update id="updateUser" parameterType="User">
            update user set name=#{name},pwd=#{pwd} where id=#{id}
        </update>
    
        <delete id="deleteUSer" parameterType="int">
            delete from user where id=#{id}
        </delete>
    </mapper>
    
  8. 业务层调用DAO层,controller层调用service层【对于该部分仍不清晰。待回顾总结】

SpringSecurity权限控制

狂神笔记:

安全

过滤器、拦截器也可以实现,但框架实现更简单。

做网站时,应该在最开始时考虑安全

架构一旦确定,不方便再修改添加安全。

shiro、springsecurity:除了类不一样,名字不一样;认证,授权(vip1,vip2,…)

​ 在框架中只需要一两个注解就可以实现,而拦截器需要复杂代码。

springsecurity

  • 功能权限
  • 访问权限
  • 菜单权限
  • …拦截器,过滤器:大量的原生代码,冗余

记住以下几个类:

  • WebSecurityConfigurerAdapter:自定义Security策略

  • AuthenticationManagerBuilder:自定义认证策略

  • EnableWebSecurity:开启WebSecurity模式

SpringSecurity中的两个主要目标是“认证”和“授权”(访问控制)

“认证”(Authentication)

“授权”(Authorization)

  1. 创建新项目,导入必要的依赖,手动导入spring security依赖

  2. 导入静态资源 [教程案例素材链接](Spring security教程案例素材(狂神说Java之SpringBoot教程集合版): 狂神SpringBoot教程IDEA版中p34中用到的页面素材,学习Spring security (gitee.com))

  3. 编写RouterController.java控制类,设置路由信息

    @Controller
    public class RouterController {
        @RequestMapping({"/","index","index.html"})
        public String index(){
            return "index";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin(){
            return "views/login";
        }
    
        @RequestMapping("/level1/{id}")
        public String toLevel1(@PathVariable("id") int id){
            return "views/level1/"+id;
        }
    
        @RequestMapping("/level2/{id}")
        public String toLevel2(@PathVariable("id") int id){
            return "views/level2/"+id;
        }
    
        @RequestMapping("/level3/{id}")
        public String toLevel3(@PathVariable("id") int id){
            return "views/level3/"+id;
        }
    }
    

    各部分路由分别对应各静态资源的文件夹位置

  4. 编写SecurityConfig.java配置类

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        //链式编程
        @Override
        protected void configure(HttpSecurity http) throws Exception {
           
            //首页所有人可以访问,功能页只有对应有权限的人才能访问
           //请求授权的规则
            http.authorizeRequests()
                    .antMatchers("/").permitAll()
                    .antMatchers("/level1/**").hasRole("vip1")
                    .antMatchers("/level2/**").hasRole("vip2")
                    .antMatchers("/level3/**").hasRole("vip3");
    
            //没有权限需要跳转到登录页,下列代码开启登录页面
            http.formLogin();
            
            //开启了注销功能
            //http.logout();
            //http.logout().logoutUrl("/");
            
            //网站防止攻击功能,csrf功能,默认开启
            http.csrf().disable(); //关闭csrf功能
            http.logout().logoutSuccessUrl("/index");
            
    
        }
    
        //认证,springboot之前的版本中可以直接使用,但目前不可以用
        //密码编码:passwordEncode
        //在新版中,增加了很多的加密方式
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //这些数据正常应该从数据库中读
            auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                    .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip1")
                    .and()
                    .withUser("jinfz").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
        }
    }
    

    注:两个方法皆为方法重写,重写后对于方法进行自己的改写(重写中方法名相同,但使用不同)

    对于数据库的授权,方式如下:

    @Autowired
    private DataSource dataSource;
    
    @Autowired
    private void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
        //ensure the passwords are encoded properly
        UserBuilder users = User.withDefaultPasswordEncoder();
        auth
            .jdbcAuthentication()
            	.dataSource(dataSource)
            	.withDefaultScheme()
            	.withUser(users.username("user").password("password").roles("USER))
    			.withUser(user.username("admin").password("password").roles("USER","ADMIN"));
    }
    

对于thymeleaf引擎下的前端部分,仅对可实现功能进行记录,不要求记住操作

P36 注销及权限控制

  1. 导入thymeleaf-spring security依赖

  2. 导入命名空间,修改index.html,判断用户登录状态,并据此判断是否显示用户名和权限,显示登陆按钮还是注销按钮

  3. 根据用户的权限(hasRole)动态显示菜单index.html

P37 记住我及首页定制

  1. 记住我

    	http.rememberMe(); //记住我功能(本质是cookie,默认保持两周)
    
  2. 首页定制

    【前端后端联调】

    打开源码 HttpSecurity.java,根据其中注解中有的功能对需要的功能进行实现

P38-P45 Shiro

  1. 与SpringBoot/SpringSecurity平级的安全框架

多看开源项目,多学习

Swagger接口文档

狂神笔记:

swagger的作用和概念

了解前后端分离

在SpringBoot中集成Swagger

前后端分离:

  • 后端:后端控制层(controller),服务层,数据访问层

  • 前端:前端控制层,视图层

    • 伪造后端数据,json交互。不需要后端,前端工程依旧能跑起来
  • 前后端如何交互==> API接口

  • 前后端相对独立,松耦合

  • 前后端甚至可以部署在不同的服务器上

产生一个问题:

  • 前后端联调,前后端人员无法做到及时协商,尽早解决

解决方案:

  • 首先制定scheme,实时更新最新的API,降低集成风险;

  • Swagger

Swagger

  • API文档与API定义同步更新

  • 直接运行,可以在线测试API接口

swagger2

swagger-ui

SpringBoot集成Swagger

  1. 新建项目,手动导入Springfox-Swagger2、SwaggerUI(对应Swagger 2.x)(Swagger 3.0需要导入springfox-boot-starter)

  2. 编写helloworld(即编写HelloController控制类)

    @RestController
    public class HelloController {
        //每个项目默认都会有一个error请求
        @RequestMapping("/hello")
        public String hello(){
            return "hello";
        }
    }
    
  3. 编写SwaggerConfig.java配置Swagger

    @Configuration
    @EnableSwagger2 //开启swagger
    public class SwaggerConfig {
    
    }
    

    此处仅是启动,并未进行详细配置(采用默认配置)

  4. 测试访问

    区别于视频中的Swagger 2.x,Swagger 3.0之后的版本需要导入springfox-boot-starter依赖,同时访问的网址修改为http://localhost:8080/swagger-ui/(或者http://localhost:8080/swagger-ui/index.html)

配置Swagger

  1. Swagger的bean实例 Docket:
@Configuration
@EnableSwagger2 //开启swagger
public class SwaggerConfig {

    //配置了Swagger的bean实例
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo());
        //看源码,完成对输入参数的设置
        //配置Swagger信息=info类

    }
    private ApiInfo apiInfo(){
        //作者信息
        Contact contact = new Contact("jinfz","http://s.weibo.com" ,"yijia7590jfz@163.com" );

        return new ApiInfo("狂神的Api文档", "Api Documentation", "v1.0",
                "urn:tos", contact, "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList());
    }
}

image-20210426163905736

  1. Swagger配置扫描接口

    @Bean
        public Docket docket(){
            return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.jinfz.swagger.controller"))
                /* 此处指定扫描的包(或者使用any()扫描全部;none()不扫描;
                   withClassAnnotation(HelloController.class)扫描注解class)*/
                .build();
            //看源码,完成对输入参数的设置
            //配置Swagger信息=info类
    
  2. 配置是否启动

return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(false)
    			//是否启动Swagger
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.jinfz.swagger.controller"))
                .build();

小问题:希望swagger只在生产环境中使用,在发布时不适使用

  • 判断是不是生产环境,flag=false
  • 注入enable(flag)
@Configuration
@EnableSwagger2 //开启swagger
public class SwaggerConfig {

    @Bean
    public Docket docket(Environment environment){ //此处需要注入接口类
        Profiles profiles=Profiles.of("dev","pro"); //此处为注解类,非实体类
        
        //获取项目环境
        boolean flag = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .enable(false)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.jinfz.swagger.controller"))
            .build();
    }
}
配置API文档的分组

不同人负责不同的部分,则可以在swagger页面选择并展示不同人的内容

.groupName("狂神")

如何配置多个分组:new多个Docket实例即可(多个Bean)

@Bean
public Docket docket2(){
    return new Docket(DocumentationType.SWAGGER_2)
        .groupName("A");
}

@Bean
public Docket docket3(){
    return new Docket(DocumentationType.SWAGGER_2)
        .groupName("B");
}

如果没有编写其他内容,则默认可以扫描全局

实体类配置
  1. 在pojo文件夹中编写User.java

    public class User {
        public String userame;
        public String password;
    }
    
  2. HelloController.java控制类中进行配置

    //只要我们的接口中,返回值中存在实体类,就会被扫描到swagger中并返回
    @PostMapping("/user")
    public User user(){
        return new User();
    }
    
  3. 为了方便他人使用swagger文档,可以为文档中的内容添加注释 SwaggerConfig.java

    @ApiModel("用户实体类")
    public class User {
        @ApiModelProperty("用户名")
        public String userame;
        @ApiModelProperty("密码")
        public String password;
    }
    

    此处可以给swagger页面中的所有东西加上注释

总结:swagger

  • 可以通过swagger给一些比较难理解的属性或者接口,添加注释信息
  • 接口文档实时更新
  • 可以在线测试

【注意点】出于安全考虑、节省内存,在正式发布时需要关闭swagger(判断环境,决定是否显示swagger)

任务

异步任务

定时任务

邮件发送-

异步任务手动方法:手动添加间隔定时(3s)【过于麻烦,实际中不可能使用】

@RestController
public class AsyncController {

    @RequestMapping("/hello")
    public String hello(){
        asyncService.hello();//停止3s,前台
        return "OK";
    }
}
@Service
public class AsyncService {

    public void hello(){
        //以下为通过设置时间间隔手动实现多线程处理。但过于麻烦
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("数据正在处理...");
    }
}

利用spring中的功能实现异步任务:

  1. 在main方法的启动类中开启异步任务

    @SpringBootApplication
    @EnableAsync //开启异步注解功能
    public class Springboot09TaskApplication {
        public static void main(String[] args) {
            SpringApplication.run(Springboot09TaskApplication.class, args);
        }
    }
    
  2. 在service中编写AsyncService.java服务类

    @RestController
    public class AsyncController {
        @Autowired
        AsyncService asyncService;
    
        @RequestMapping("/hello")
        public String hello(){
            asyncService.hello();//停止3s,前台
            return "OK";
        }
    }
    
  3. 在service层中进行配置

    @Service
    public class AsyncService {
        
        @Async
        //告诉spring这是一个异步方法
    
        public void hello(){
            //以下为通过设置时间间隔手动实现多线程处理。但过于麻烦
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("数据正在处理...");
        }
    }
    

    分两步:在方法上添加注解,在spring启动类中开启这个功能

邮件任务

使用springboot完成邮件发送

  1. pom.xml中添加spring-boot-starter-mail配置

    <!--javax:mail配置-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    
  2. 在application.properties中配置邮箱信息

    spring.mail.username=yijia7590jfz@163.com
    spring.mail.password=xxxxxxxxxxx//此处为pop3/smtp中的授权码,需手动获取
    spring.mail.host=smtp.163.com
    #qq会有加密验证,163没有
    
  3. 对邮件发送功能进行测试,在测试类中编写代码

    @Autowired
    JavaMailSenderImpl mailSender;
    @Test
    void contextLoads1() {
        //一个简单的邮件
        SimpleMailMessage mailMessage = new SimpleMailMessage();
    
        mailMessage.setSubject("你好啊");
        mailMessage.setText("每天都要开心啊");
        mailMessage.setTo("yijia7590jfz@163.com");
        mailMessage.setFrom("yijia7590jfz@163.com");
    
        mailSender.send(mailMessage);
    
    }
    
    @Test
    void contextLoads2() throws MessagingException {
        //一个复杂的邮件
        MimeMessage mimeMessage = mailSender.createMimeMessage();
    
        //组装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"UTF-8");
        //此处有异常,在更多操作中对异常进行抛出(throws)
        
        helper.setSubject("每天都好");
        helper.setText("<p style='color:red'>希望每天都能快乐度过~</p>",true);
        //此处可以对发送的文本进行html格式编辑,需在后方设置html:true,以支持html
        
    	//添加附件,此处使用相对路径
        helper.addAttachment("1.jpg", new File("C:\\Users\\18241\\Desktop\\1.jpg"));
        helper.setTo("yijia7590jfz@163.com");
        helper.setFrom("yijia7590jfz@163.com");
    
        mailSender.send(mimeMessage);
    }
    

    此处仅为测试,实际应该放在controller或者service中。可以封装为方法:

    /**
         * @Param html
         * @Param subject
         * @Param text
         * 
         * 在方法中,需要对导入的参数进行解释,以便来人
    
         */
    public void sendMail(Boolean html,String subject,String text) throws MessagingException {
        //一个复杂的邮件
        MimeMessage mimeMessage = mailSender.createMimeMessage();
    
        //组装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,html);
        //此处有异常,在更多操作中对异常进行抛出(throws)
        helper.setSubject(subject);
        helper.setText(text,true);
    
        helper.addAttachment("1.jpg", new File("C:\\Users\\18241\\Desktop\\1.jpg"));
        helper.setTo("yijia7590jfz@163.com");
        helper.setFrom("yijia7590jfz@163.com");
    
        mailSender.send(mimeMessage);
    }
    

定时任务

用于发布定时任务。

由于学习期需要完成的项目中暂时未想到此功能,故暂时跳过。

【P53】

附:出现的问题及解决办法

maven无法打jar包

打jar包方式:

双击package即可开始打包

image-20210418105030168

出现的问题:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources) on project springboot-01-helloworld: Input length = 1 -> [Help 1]

解决办法:

修改pom文件中的依赖(第一次修改完成后需要重启项目)原文链接

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>

        <!--在这里修改版本-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.4.3</version>
        </plugin>
        <!---->

    </plugins>
</build>

其他可能的解决办法:在设置中将java版本号改为实际的版本 原文链接

解决问题后的显示:

image-20210418105637815

未找到maven插件

未找到插件 ‘org.springframework.boot:spring-boot-maven-plugin:’

**解决办法:**添加版本号

解决办法

问题分析

报错:Error resolving template [index]

Springboot+thymeleaf+mybatis 报Error resolving template [index], template might not exist的异常

小技巧

  • 代码块统一向前缩进:

    shift+Tab

小功能

可以更改标签页的图标,替换成自定义图片(新版不可用,需要自寻找方法)方法链接

image-20210419151756288

阅读源码过程中的问题

阅读源码过程中的一些单词:

implement实现

metadata元数据(源数据?)

attributes属性

properties属性(配置类?)

注解介绍

@ResponseBody

@ResponseBody详解

@ConfigurationProperties(prefix = “person”):绑定指定的加载 person.java

PO、VO、POJO、DTO、DAO、Service包等常见包的理解

@Validated :信息合法性验证

前后端连接部分

展示员工列表部分中的代码:Model model的作用是将其返回给前端!!!

Mybatis部分:对于MVC进行解释:

​ C,即controller层,负责前端和后端的对接;

​ M,数据和业务;

​ V,html。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值