springboot学习笔记

1.yaml

1.1配置文件格式

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的

  • application.properties

    • 语法结构 :key=value

  • application.yml

    • 语法结构 :key:空格 value

1.2给实体类注入

1.2.1简单类

①在springboot项目中的resources目录下新建一个文件 application.yml

②新建一个实体类,注意加入有参无参构造,get、set、tostring方法

@Component //注册bean
public class Dog {
    @Value("阿黄")
    private String name;
    @Value("18")
    private Integer age;
}

 ③在SpringBoot的测试类下注入狗狗输出一下;


@SpringBootTest
class DemoApplicationTests {

    @Autowired //将狗狗自动注入进来
    Dog dog;

    @Test
    public void contextLoads() {
        System.out.println(dog); //打印看下狗狗对象
    }

}

1.2.3复杂类


/*
@ConfigurationProperties作用:
将配置文件中配置的每一个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@Component //注册bean
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}

yaml注入属性


person:
  name: qinjiang
  age: 3
  happy: false
  birth: 2000/01/01
  maps: {k1: v1,k2: v2}
  lists:
   - code
   - girl
   - music
  dog:
    name: 旺财
    age: 1

开启注解@ConfigurationProperties(prefix="")需要导入依赖

@PropertySource(value="")加载指定的配置文件


<!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

1.3配置文件占位符


person:
    name: qinjiang${random.uuid} # 随机uuid
    age: ${random.int}  # 随机int
    dog:
      name: ${person.hello:other}_旺财 //如果没有赋值就默认为hello
      age: 1

1.4注解对比

@value("${user.name}")需要为每个属性单独注解赋值,比较麻烦

@ConfigurationProperties(prefix="")则只需要在类之前注释一次即可

1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加

2、松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下

3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性

4、复杂类型封装,yml中可以封装对象 , 使用value就不支持

1.5多环境切换

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件

优先级1:项目路径下的config文件夹配置文件优先级2:项目路径下配置文件优先级3:资源路径下的config文件夹配置文件优先级4:资源路径下配置文件

server:
  port: 8081
#选择要激活那个环境块
spring:
  profiles:
    active: prod

---
server:
  port: 8083
spring:
  profiles: dev #配置环境的名称


---

server:
  port: 8084
spring:
  profiles: prod  #配置环境的名称

2.JSR303数据校验 

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY.
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 Date 和 Calendar 对象是否在当前时间之前  
@Future     验证 Date 和 Calendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则

.......等等
除此以外,我们还可以自定义一些数据校验规则

3.thymeleaf

类似于视图解析器

3.1导入依赖

<!--thymeleaf-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

3.2导入命名空间的约束

需要在html文件中导入命名空间的约束,方便提示;

xmlns:th="http://www.thymeleaf.org"

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>测试页面</h1>
<div th:text="${msg}"></div>
<div th:utext="${msg}"></div>
<<hr>
<h3 th:each="user:${list}" th:text="${user}"></h3>
</body>
</html>

th:utest: 这个会对后端传得数据进行转义,如<h1></h1>

th:each="user:${users}" th:test="${user}" 即拿到users类中中的每一个对象,并且引用

3.3测试

编写TestController

@RequestMapping("/t1")
    public String test1(Model model){
        model.addAttribute("msg","<h1>hello world</h1>");
        model.addAttribute("list", Arrays.asList("kuangsheng","liyukang"));
        //classpath:/templates/test.html
        return "test";
    }

4.mvc自动配置

@EnableWebMvc将WebMvcConfigurationSupport组件导入进来了;

而导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能!

所以springboot可以全面接管springmvc的自动配置,但是开发中不推荐如此使用。

5.员工管理系统

5.1首页配置

所有的静态资源都需要由thymeleaf接管(导依赖+html标签头加约束:xmlns:th="http://www.thymeleaf.org"),其中css样式应该放在static目录下,而html则需要放在 template下。注意:跳转地址如(src,href这些都需要变成th:src="@{/css/signin.css}" ,th:href)

5.2国际化

即一个页面中可以实现找中英文切换的效果

5.3登陆

5.3.1工具类

①在MyMvcConfig工具类中实现webMvcConfigurer

然后重写(ctrl+O)addViewControllers方法,这里的registry.addViewController("url").setViewName("html") 即访问url时就会跳转到html页面。

②重写addInterceptor(new HandlerIntercepror),链式编程调用addPathPatterns来添加限制路径(/**表所有路劲)即excludePathPatterns

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
        registry.addViewController("/main.html").setViewName("dashboard");
    }

    @Bean
    public MyLocalResolver localResolver() {
        return new MyLocalResolver();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginHandlerInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/user/login","/index.html","/","/css/*","/js/**","/img/**");
    }
}

5.3.2controller

编写LoginController,

  • 登录成功时给session注入属性,让loginUser携带有username,还有就是重定向到main页面;
  • 登录失败时就会利用model给前端传去错误信息,并返回登录页。
@Controller
public class LoginController {
    @RequestMapping("/user/login")
    public String hello(@RequestParam("username") String username, @RequestParam("password") String password, Model model, HttpSession session){
        if (!StringUtils.isEmpty(username) &&"123456".equals(password)){
            session.setAttribute("loginUser",username);
            return "redirect:/main.html";
        }else {
            model.addAttribute("msg","用户名于或者密码错误");
            return "index";
        }
    }
}

LoginHandlerInterceptor

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

5.4展示员工

①在首页点击员工管理时会跳转到员工管理页面,通过th:href="@{/url}"实现绑定   

②跳转到emps,首先会调用dao层去查所有员工集合,并且通过model把集合返回给前端

model.addAttribute("msg",list);msg==给前端引用的id 

③跳转到emp下的list.html

5.4.1前端

<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>

list.html 注意th:each="(emp:${emps})"用法,接着就可以通过¥{emp.get()}引用其属性

  <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>department</th>
                        <th>birth</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr th:each="emp:${allEmp}">
                        <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.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
                        <td>
                            <button class="btn btn-sm btn-primary">编辑</button>
                            <button class="btn btn-sm btn-danger">删除</button>
                        </td>

                    </tr>

                    </tbody>
                </table>
            </div>
        </main>

5.4.2controller

@Controller
public class EmployeeController {
    @Resource
    private EmployeeDao employeeDao;

    @RequestMapping("/emps")
    public String getAllEmp(Model model){
        Collection<Employee> allEmp = employeeDao.getAll();
        model.addAttribute("allEmp",allEmp);
        return "emp/list";

    }
}

5.5增加员工

在员工展示页面新增按钮,采用restful风格绑定跳转方法(在a标签中默认请求方式都是以get请求)

<h2>
     <a class="btn btn-sm btn-success" th:href="@{/emp}">
                        添加员工
     </a>
 </h2>

在controller层中定义toAddPaper,然后跳转到emp下的add.html页面

 @GetMapping("/emp")
    public String toAddPaper(Model model){
        Collection<Department> departments = departmentDao.getDepartments();
        model.addAttribute("departments",departments);
        return "emp/add";
    } 
@PostMapping("/emp")
    public String addEmp(Employee employee){
        //添加操作
        System.out.println("debug=>"+employee);
        employeeDao.add(employee);
        //添加成功重定向到员工页面
        return "redirect:/emps";
    }

add.html页面复制list.html,然后就主要修改main里面的内容,即添加一个表单,然后当我们点击提交按钮时,这个form表单(注意里面的input属性都要添加一个name做标识)的th:action属性就会到控制器(controller)下寻找emp下以post方法请求的方法

 <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/emp}" method="post">
                <div class="form-group">
                    <label>LastName</label>
                    <input type="text" name="lastName" class="form-control" placeholder="海绵宝宝">
                </div>
                <div class="form-group">
                    <label>Email</label>
                    <input type="email" name="email" class="form-control" placeholder="1176244270@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 class="form-group">
                        <label>department</label>
                        <select class="form-control" name="department.id">
                            <option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}">1</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label>Birth</label>
                        <input type="text"name="birth" class="form-control" placeholder="">
<!--&lt;!&ndash;                       -->

                        <button class="btn btn-primary">添加</button>
                    </div>
                </div>
            </form>
        </main>

5.6修改员工

前端部分同样是定义一个a标签(注意这里我们需要给后端一个id让其去回显员工信息)

然后里面去引用地址th:href="@{  }"  ${}这个则是值引用

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

controller,控制器编写toUpdatePaper方法,注意这里我们需要利用前端传来的id去回显员工信息,我们利用这个id去查找信息,然后再通过model给前端回显。

而且这里我们还需要员工的部门信息,所以我们需要把所有部门都放在集合里

最后我们跳转到update页面

@GetMapping("/emp/{id}")
    public String toUpdatePaper(@PathVariable("id") Integer id,Model model){
//        回显员工信息
        Employee employee = employeeDao.getById(id);
        model.addAttribute("employee",employee);
        Collection<Department> departments = departmentDao.getDepartments();
        model.addAttribute("departments",departments);

        return "emp/update";
    }
    @PostMapping("/updateEmp")
    public String updateEmp(Employee employee){
        //添加操作
        System.out.println("debug=>"+employee);
        employeeDao.add(employee);
        //添加成功重定向到员工页面
        return "redirect:/emps";
    }

update.html中我们利用${employee.getID}来取值 ,在部门那里我们需要去遍历所有部门集合,然后通过th:select去选择部门id跟用户的部门id一致的。

最后通过form标签中的action方法再跳转到控制器中的updateEmp方法

注意前端每个传给后端的参数都有自己的name,这个name要与mapper.xml文件中保持一致,后端才能接受到

<body>

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

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

        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/updateEmp}" method="post">
                <input type="hidden" name="id" th:value="${employee.getId()} ">
                <div class="form-group">
                    <label>LastName</label>
                    <input type="text" name="lastName" class="form-control" th:value="${employee.getLastName()}">
                </div>
                <div class="form-group">
                    <label>Email</label>
                    <input type="email" name="email" class="form-control" th:value="${employee.getEmail()}">
                </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" th:checked="${employee.getGender()==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" th:checked="${employee.getGender()==0}">
                        <label class="form-check-label">女</label>
                    </div>

                    <div class="form-group">
                        <label>department</label>
                        <select class="form-control" name="department.id">
                            <option th:selected="${dept.getId()==employee.getDepartment().getId()}" th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}">1</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label>Birth</label>
                        <input th:value="${#dates.format(employee.getBirth(),'yyyy/MM/dd HH:mm')}" type="text"name="birth" class="form-control" placeholder="">
<!--&lt;!&ndash;                       -->

                        <button class="btn btn-primary">修改</button>
                    </div>
                </div>
            </form>
        </main>

    </div>
</div>

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="asserts/js/jquery-3.2.1.slim.min.js"></script>
<script type="text/javascript" src="asserts/js/popper.min.js"></script>
<script type="text/javascript" src="asserts/js/bootstrap.min.js"></script>

<!-- Icons -->
<script type="text/javascript" src="asserts/js/feather.min.js"></script>
<script>
    feather.replace()
</script>

<!-- Graphs -->
<script type="text/javascript" src="asserts/js/Chart.min.js"></script>
<script>
    var ctx = document.getElementById("myChart");
    var myChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
            datasets: [{
                data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
                lineTension: 0,
                backgroundColor: 'transparent',
                borderColor: '#007bff',
                borderWidth: 4,
                pointBackgroundColor: '#007bff'
            }]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: false
                    }
                }]
            },
            legend: {
                display: false,
            }
        }
    });
</script>



</body>

5.7删除员工

在删除的按钮中添加th:href="";随后点击就会调到控制器

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

控制器中

 @GetMapping("/del/{id}")
    public String deleteEmp(@PathVariable("id") Integer id){
        System.out.println("删除的员工id"+id);
        employeeDao.delete(id);
        return "redirect:/emps";
    }

5.8注销跟404

注销就是在注销按钮绑定一个logout跳转路径

<a class="nav-link" th:href="@{/user/logout}">注销</a>

在loginController中写出对应方法,然后只需要将session设置过期还有重定向就可以了。

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

    }

404就是在template下新建一个error包然后把404.html放入其中就可以了

6.怎么写一个网站

7.整合jdbc

jdbcTemplate就是一个模版,并且他已经被spring容器接管,所以我们可以直接注入,然后调用里面的方法。注意这里的增删改都是用的的update方法。

@RestController
public class UserController {
    @Autowired
    JdbcTemplate jdbcTemplate;

    @GetMapping("select")
    public List<Map<String, Object>> select(){
        String sql = "select * from mybatis.tb_user";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return maps;
    }
    @GetMapping("addUser")
    public String addUser(){
        String sql = "insert into mybatis.tb_user(username,password,gender,addr) values('lyk','123456','男','梅州')";

        jdbcTemplate.update(sql);
        return "addUser--Ok";
    }
    @GetMapping("updateUser/{id}")
    public String updateUser(@PathVariable("id") Integer id){
        String sql = "update mybatis.tb_user set username = ?,password = ? where id = "+id;
        Object[] objects = new Object[2];
        objects[0] = "李二";
        objects[1] = "damage";
        jdbcTemplate.update(sql,objects);
        return "updateUser--Ok";
    }
    @GetMapping("deleteUser/{id}")
    public String deleteUser(@PathVariable("id") Integer id){
        String sql = "delete from mybatis.tb_user where id = "+id;
        jdbcTemplate.update(sql,id);
        return "deleteUser--Ok";
    }
}

 8.整合druid

1、添加上 Druid 数据源依赖。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.21</version>
</dependency>

2、切换数据源;默认使用 com.zaxxer.hikari.HikariDataSource 数据源,但可以 通过 spring.datasource.type 指定数据源。

spring:
  datasource:
    username: root
    password: 123456
    #?serverTimezone=UTC解决时区的报错
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #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

3.添加log4J

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

4.在DruicConfig中配置数据源监控,还有数据源过滤器等

//配置 Druid 监控管理后台的Servlet;
//内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式
@Bean
public ServletRegistrationBean statViewServlet() {
    ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

    // 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 
    // 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到
    Map<String, String> initParams = new HashMap<>();
    initParams.put("loginUsername", "admin"); //后台管理界面的登录账号
    initParams.put("loginPassword", "123456"); //后台管理界面的登录密码

    //后台允许谁可以访问
    //initParams.put("allow", "localhost"):表示只有本机可以访问
    //initParams.put("allow", ""):为空或者为null时,表示允许所有访问
    initParams.put("allow", "");
    //deny:Druid 后台拒绝谁访问
    //initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问

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

9.整合mybatis(重点)

新建项目时注意勾选springweb,jdbc Api,mysql Driver。

这里就会生成对应的依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

9.1导依赖

导入mybatis依赖

 <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
 </dependency>

9.2配置文件

两种方法,第一种是application.properties  第二种是application.yml

主要是编写数据库四个连接信息,还有就是整合mybatis起别名还有扫描包位置

这里连接数据库的用户名记得是username,然后mapper-location是当mapper接口和mapper接口对应的配置文件命名或路径不同时使用,classpath*:

spring.application.username=springboot-mybatis
spring.datasource.name=root
spring.datasource.password=654321
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
#整合mybatis
#给pojo包下的所有类起别名,默认包名小写,这样在mapper.xml文件中的resultType直接写别名
mybatis.type-aliases-package=com.itheima.pojo
#mapper.xml文件所在位置,classpath这里表resources
mybatis.mapper-locations=classpath*:mybatis/mapper/*.xml

spring:
  datasource:
    username: root
    password: 123456
    #?serverTimezone=UTC解决时区的报错
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #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

9.3测试

测试这些配置成功,可以在test下注入数据源,然后看看是否可以获得datasource.

   @Autowired
    DataSource  dataSource;
    @Test
    void contextLoads() throws SQLException {
        System.out.println(dataSource.getClass());
    }

9.4编写类

9.4.1pojo

根据数据库中信息,新建一个对应类,加上构造函数。注意如果数据库中字段为brang_name 则在类中跟根据驼峰命名规则应该为brandName;这个还需要再application.properties中开启配置

# 开启驼峰命名与数据库字段相匹配
mybatis.configuration.map-underscore-to-camel-case=true
@NoArgsConstructor
@Data
public class User {
    private int id;
    private String username;
    private String password;
    private String gender;
    private String addr;

    public User(String username, String password, String gender, String addr) {
        this.username = username;
        this.password = password;
        this.gender = gender;
        this.addr = addr;
    }
    public User(int id, String username, String password, String gender, String addr) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.gender = gender;
        this.addr = addr;
    }
}

9.4.2mapper

@Mapper:这个是mybatis特有的注解,即会扫描到这个包 <=> 在主程序加上ComponentScan

mapper找不到可能是mybatis-spring-boot-starter版本太低

@Mapper
@Repository
public interface UserMapper {
    User queryUserById(Integer id);
    List<User> queryUsers();

    int addUser(User user);
    int deleteUser(Integer id);
    int updateUserById(User user);
}

9.4.3mapper.xml

这里的resultType由于我们开启了缩写,所以我们可以直接写Pojo包下的类名的小写来简化

<?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.itheima.mapper.UserMapper">
    <insert id="addUser" parameterType="user">
        insert into mybatis.tb_user(username, password, gender, addr) VALUES (#{username},#{password},#{gender},#{addr});
    </insert>
    <update id="updateUserById" parameterType="user">
        update mybatis.tb_user set username = #{username} , password = #{password},gender = #{gender},addr = #{addr} where id = #{id};
    </update>
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.tb_user where id = #{id}
    </delete>

    <select id="queryUserById" resultType="com.itheima.pojo.User" parameterType="java.lang.Integer">
        select *
        from mybatis.tb_user where id = #{id};
    </select>
    <select id="queryUsers" resultType="user">
        select * from mybatis.tb_user;
    </select>
    
    <select id="queryBrand" resultType="brand" >
        select *
        from mybatis.tb_brand where brand_name = #{brandName};
    </select>
</mapper>

9.4.4controller

注意就算8080服务正常开启,也可能404,需要我们去controller中调用测试。

@RestController
public class UserController {
    @Autowired
    private UserMapper userMapper;
    
    @GetMapping("/test")
    public String test(){
        return "test";
    }

    @GetMapping("/queryUserById/{id}")
    public User queryUserById(@PathVariable("id") Integer id){
        System.out.println("id"+id);
        return userMapper.queryUserById(id);
    }

    @GetMapping("/allUser")
    public List<User> queryUsers(){
        List<User> users = userMapper.queryUsers();
        for (User user : users) {
            System.out.println(user);
        }
        return users;
    }

    @GetMapping("deleteUser/{id}")
    public String deleteUser(@PathVariable("id") int id){
        userMapper.deleteUser(id);
        return "deleteUser -ok";
    }

    @GetMapping("/addUser")
    public String addUser(){
        userMapper.addUser(new User("fei","654321","男","梅州"));
        return "addUser -ok";
    }
    @GetMapping("updateUser")
    public String updateUser(){
        userMapper.updateUserById(new User(7,"lyk","654321","男","汕头"));
        return "updateUser-ok";
    }

    @GetMapping("/queryBrandByName")
    public Brand queryBrandByName(){
        Brand brand = userMapper.queryBrand("小米");
        return brand;
    }
}

9.5员工管理系统再完善

在原来的基础上整合进去数据库,即导依赖,编写配置文件,测试数据库数据源。接着就可以编写实体类,然后就是mapper接口还有对应xml文件,最后在控制层调用mapper接口。

9.5.1实体类

Employee

@AllArgsConstructor
@Data
@NoArgsConstructor
public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private String gender;
    private String department;
    private Date birth;
    
}

Department

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

9.5.2mapper

EmployMapper

@Mapper
@Repository
public interface EmployMapper {
    List<Employee> getAllEmp();
    Employee getEmpById(int id);
    int addEmp(Employee employee);
    int deleteEmpById(int id);
    int updateEmp(Employee employee);
}

DepartmentMapper

@Mapper
@Repository
public interface DepartmentMapper {
    List<Department> getAllDept();
}

9.5.2mapper.xml

DepartmentMapper.xml

<?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.itheima.dao.DepartmentMapper">
    <select id="getAllDept" resultType="com.itheima.pojo.Department">
        select * from emp_manage.dept;
    </select>
</mapper>

EmployMapper.xml

<?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.itheima.dao.EmployMapper">
    <insert id="addEmp">
        insert into emp_manage.emp(last_name, email, gender, department, birth) values (#{lastName},#{email},#{gender},#{department},#{birth})
    </insert>

    <update id="updateEmp">
        update emp_manage.emp
        set last_name = #{lastName} ,email =#{email},gender =#{gender},department=#{department},birth = #{birth}
        where id = #{id}
    </update>
    <delete id="deleteEmpById">
        delete  from emp_manage.emp where id = #{id}
    </delete>

    <select id="getAllEmp" resultType="com.itheima.pojo.Employee">
        select * from emp_manage.emp ;
    </select>
    <select id="getEmpById" resultType="com.itheima.pojo.Employee" parameterType="int">
        select * from emp_manage.emp where id = #{id}
    </select>
</mapper>

9.5.3controller

重定向的会刷新页面,一般用于更新数据之后的操作,而跳转到某个页面的时候一般直接return

@Autowired
    private EmployMapper employMapper;
    @Autowired
    private DepartmentMapper departmentMapper;
    @RequestMapping("/emps")
    public String getALlEmp(Model model){
        List<Employee> allEmp = employMapper.getAllEmp();
        for (Employee emp : allEmp){
            System.out.println(emp);
        }
        model.addAttribute("allEmp",allEmp);
        return "/emp/list";
    }

    @GetMapping("/emp")
    public String toAddPaper(Model model){
//        Collection<Department> departments = departmentDao.getDepartments();
//        model.addAttribute("departments",departments);
        List<Department> departments = departmentMapper.getAllDept();
        model.addAttribute("departments",departments);
        return "emp/add";
    }
    @PostMapping("/emp")
    public String addEmp(Employee employee){
        System.out.println("添加的员工信息:"+employee);
        employMapper.addEmp(employee);
        return "redirect:/emps";
    }

    @GetMapping("/emp/{id}")
    public String  toUpdatePaper(@PathVariable("id") int id,Model model){
        Employee employee = employMapper.getEmpById(id);
        System.out.println("回显员工:"+employee);
        model.addAttribute("employee",employee);
        List<Department> allDept = departmentMapper.getAllDept();
        model.addAttribute("departments",allDept);
        return "emp/update";
    }

    @PostMapping("/updateEmp")
    public String updateEmp(Employee employee){
        //添加操作
        System.out.println("debug=>"+employee);
        employMapper.updateEmp(employee);
        //添加成功重定向到员工页面
        return "redirect:/emps";
    }
    @GetMapping("/del/{id}")
    public String deleteEmp(@PathVariable("id") Integer id){
        System.out.println("删除的员工id"+id);
        employMapper.deleteEmpById(id);
        return "redirect:/emps";
    }

10.Swagger

前后端通过API进行交互,为响应前后端需求的变更,故出现Swagger。优点如下:

  • Restful Api 文档在线自动生成器 => API 文档 与API 定义同步更新

  • 直接运行,在线测试API

10.1Swagger使用

  • 新建一个个springboot 项目
  • 导入依赖(swagger2,swagger-ui)这是swagger2的两个依赖,这两个的版本与springboot的版本有关系
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.9.2</version>
</dependency>
  • 新建一个HelloController
  • 使用Swagger,我们需要编写一个配置类-SwaggerConfig来配置 Swagger

@Configuration
@EnableSwagger2WebMvc
public class SwaggerConfig {

}
  •  访问 Http://localhost:8080/swagger-ui.html 即可访问到swagger页面

10.2配置

10.2.1配置文档信息及扫描接口

1.Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger具体参数。
参数解释如下:

.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口

注意这里的basePackage可以更换为其他方式,有扫描所有接口的any;还有

withMethodAnnotation(GetMapping.class)只扫描get请求;withClassAnnotation(Controller.class)只扫描有controller注解的类中的接口)

.path是配置过滤请求,.paths(PathSelectors.ant("/kuang/**")),这里只扫描请求以/kuang开头的接口

2.通过apiInfo()属性配置文档信息

3.Docket 实例关联上 apiInfo()

即return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())

@Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.controllers"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("My API")
                .description("API documentation for My Application")
                .version("1.0")
                .build();
    }

10.2.2配置swagger开关

通过docket中的enable()方法,若为false,swagger将不能在浏览器中访问,这个主要应用在服务上线后,为了接口安全性考虑。

多服务即不同的配置文件,一般有test,dev两种,在application.properties中配置了不同的端口号

@Bean
public Docket docket(Environment environment) {
   // 设置要显示swagger的环境
   Profiles of = Profiles.of("dev", "test");
   // 判断当前是否处于该环境
   // 通过 enable() 接收此参数判断是否要显示
   boolean b = environment.acceptsProfiles(of);
   
   return new Docket(DocumentationType.SWAGGER_2)
      .apiInfo(apiInfo())
      .enable(b) //配置是否启用Swagger,如果是false,在浏览器将无法访问
      .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
      .apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
       // 配置如何通过path过滤,即这里只扫描请求以/kuang开头的接口
      .paths(PathSelectors.ant("/kuang/**"))
      .build();
}

10.2.3配置Api分组

多个docket代表不同的分组,不同的docket访问到的接口都是不一样的,有了这一分组,每个人所负责的Api就可以很明显的看出,这只需要在docket中引用groupName()方法即可配置分组:

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

10.3常用注解

@Api(tags = "xxx模块说明")

@ApiModel为类添加注释

@ApiModelProperty为类属性添加注释

@ApiOperation("xxx接口说明")

@ApiParam("xxx参数说明")

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

@ApiOperation("狂神的接口")
@PostMapping("/kuang")
@ResponseBody
public String kuang(@ApiParam("这个名字会被返回")String username){
   return username;
}

11.任务

11.1异步任务

异步任务即前台瞬间响应,后台代码依旧执行!这就要依靠springboot线程池的功能,要使用这一功能我们需要在主程序上添加@EnableAsync注解,还有在方法上添加@Async注解,告诉spring这是一个异步任务.

@Service
public class AsyncService {
    @Async //告诉spring这是一个异步方法
    public void hello(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("正在处理");
    }
}

@RestController
public class AsyncController {
    @Autowired
    AsyncService asyncService;
    @RequestMapping("hello")
    public String hello(){
        asyncService.hello();
        return "hello";
    }
}

@SpringBootApplication
@EnableAsync//开启异步注解功能
public class SpringbootTask01Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootTask01Application.class, args);
    }
}


11.2定时任务

定时任务即在方法上加@Scheduled(corn = "")注解,设置何时执行任务,一般用于日志的记录

开启这个功能需要在主程序上增加@EnableScheduling 

corn表达式:0 0 12 * * ?   每天中午12点触发    0/2 * * * * ?   表示每2秒 执行任务

                  (*表任意,?表日/星期冲突)

@Service
public class ScheduleService {
    
    //从小到大 秒 分 时 日 月 星期
    //每周的四月2号18点03分20秒
    @Scheduled(cron = "20 3 18 2 4 0-7")
    public void hello2(){
        System.out.println("damage....");
    }
}

@SpringBootApplication
@EnableAsync//开启异步注解功能
@EnableScheduling//开启基于注解的定时任务
public class SpringbootTask01Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootTask01Application.class, args);
    }
}

11.3邮件任务

1.引入依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2.配置文件

spring.mail.username=24736743@qq.com
spring.mail.password=你的qq授权码
spring.mail.host=smtp.qq.com # qq需要配置ssl spring.mail.properties.mail.smtp.ssl.enable=true

获取授权码:在QQ邮箱中的设置->账户->开启pop3和smtp服务 

3.测试

注入一个mailSender ,这个是javaMailSenderImpl封装的交给spring管理

新建一个SimpleMailMessage,然后设置邮件的主题,正文,接收人,发送人

最后通过mailSender的send方法把message发送出去

@Autowired
JavaMailSenderImpl mailSender;

@Test
public void contextLoads() {
   //邮件设置1:一个简单的邮件
   SimpleMailMessage message = new SimpleMailMessage();
   message.setSubject("通知-明天来狂神这听课");
   message.setText("今晚7:30开会");

   message.setTo("24736743@qq.com");
   message.setFrom("24736743@qq.com");
   mailSender.send(message);
}

@Test
public void contextLoads2() throws MessagingException {
   //邮件设置2:一个复杂的邮件
   MimeMessage mimeMessage = mailSender.createMimeMessage();
   MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);

   helper.setSubject("通知-明天来狂神这听课");
   helper.setText("<b style='color:red'>今天 7:30来开会</b>",true);

   //发送附件
   helper.addAttachment("1.jpg",new File(""));


   helper.setTo("24736743@qq.com");
   helper.setFrom("24736743@qq.com");

   mailSender.send(mimeMessage);
}

12.分布式系统

分布式系统是利用多台机器来处理大量数据,实现一台机器所无法做到的数据处理。

12.1RPC

Rpc是指远程过程调用,是一种进程间通信方式,他是一种技术思想,又叫做分布式服务架构,是在垂直应用架构(MVC)上将核心业务抽取出来,实现复用。两个核心:通讯,序列化。

12.2zookeeper

下载:在官网下载了最新版3.9.2,

运行:点击/bin/zkServer.cmd ,初次运行会报错(一闪而过:所以我们需要再最后加上一个pause看错误提示),没有zoo.cfg配置文件;

配置:将conf文件夹下面的zoo_sample.cfg复制一份改名为zoo.cfg即可。dataDir=“”(这里是临时数据存储的目录,可以在子目录中创建一个data,之后写其绝对路径)

测试:使用zkCli.cmd测试

create –e /kuangshen 123:创建一个kuangshen节点,值为123

图片

get /kuangshen:获取/kuangshen节点的值

12.3dubbo

dubbo就是一个jar包,能够帮你的java程序连接到zookeeper,并利用zookeeper消费、提供服务。

官方提供了一个可视化的监控程序(页面)dubbo-admin,不过这个监控即使不装也不影响使用。

12.4服务拆分

springboot+dubbo+zookeeper

导入依赖,在服务提供者跟消费者模块中都导入。

<!--dubbo-->
<!-- Dubbo Spring Boot Starter -->
<dependency>
   <groupId>org.apache.dubbo</groupId>
   <artifactId>dubbo-spring-boot-starter</artifactId>
   <version>2.7.3</version>
</dependency>
<!--zookeeper-->
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
   <groupId>com.github.sgroschupf</groupId>
   <artifactId>zkclient</artifactId>
   <version>0.1</version>
</dependency>
<!-- 引入zookeeper -->
<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-framework</artifactId>
   <version>2.12.0</version>
</dependency>
<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-recipes</artifactId>
   <version>2.12.0</version>
</dependency>
<dependency>
   <groupId>org.apache.zookeeper</groupId>
   <artifactId>zookeeper</artifactId>
   <version>3.4.14</version>
   <!--排除这个slf4j-log4j12-->
   <exclusions>
       <exclusion>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-log4j12</artifactId>
       </exclusion>
   </exclusions>
</dependency>

配置springboot中的参数,两个模块都需要,但是消费者模块中只需要前两个。

#当前应用名字
dubbo.application.name=provider-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#扫描指定包下服务
dubbo.scan.base-packages=com.kuang.provider.service

最后就是利用@Reference在消费者中注入服务者,然后实现不同模块服务的调用。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值