复习

  1. spring-boot的使用
  2. 特征
    1. 独立的应用程序
    2. 内嵌式的tomcat、jetty或undertow
    3. 提供starter依赖,简化构建配置
    4. 自动配置
    5. 提供生产级功能,比如:运行指标、健康检查、外化配置
    6. 绝不使用代码生成与xml
  3. 原理
    1. starter依赖
      1. 简化依赖(依赖传递)
      2. 自动配置
      3. 外化配置(将散落在不同的配置文件中的配置,集中到外部的配置文件application.yml中)
      4. 命名约定(官方:spring-boot-starter-xxx 民间:xxx-spring-boot-starter)
    2. spring-boot-maven插件
      1. 运行 mvn spring-boot:run
      2. 打包 mvn clean package (fatjar) java -jar xxxx.jar
    3. parent —> spring-boot-starter-parent —> spring-boot-dependencies (依赖版本)
  4. 自动配置
    1. @EnableAutoConfiguration 启动自动配置
    2. spring-boot在启动时,扫描starter依赖根目录下的META-INF/spring.factories,得到自动配置类的路径
    3. 自动配置类,@Configuration标记为配置类 @Bean 提供了集成到spring所需要的bean,实现自动配置
    4. 自动配置类关联一个配置属性类@EnableConfigurationProperties(配置类),可以将配置类的属性用于自动配置
    5. 配置属性类 @ConfigurationProperties(prefix=”配置前缀”) application.yml中配置项格式就是 配置前缀.属性名;将外化配置文件中的配置读入到该属性类,用于自动配置
  5. 集成springmvc+mybatis spring-boot三板斧
    1. 加依赖 starter依赖
    2. 修改配置文件 application.yml
    3. 加注解

作业

  1. 学生管理(增删改查)
    1. 学生姓名 学号 性别 年龄 专业 入学时间 咨询老师 班级
    2. 学生注册 / 学生毕业 / 学生分页查询

建表规范

  1. 学生表,有哪些字段?需求
    1. 隐性的需求 举例: 用户表的 最后一次登录时间
  2. 字段命名,英文,下划线分词,见名知意,不要用缩写,不要用拼音
  3. 字段数据类型的选择
  4. 关联关系
    1. 1:1 任意,甚至双边
    2. 1:m/ m:1 存在多的一方
    3. m:n 中间表
  5. 主键,使用int,自增
  6. 给表和字段加注释
  7. 有默认字段 raw_add_time记录新增时间 raw_update_time记录更新时间
  1. drop database if exists edu_56;
  2. create database edu_56;
  3. drop table if exists edu_student;
  4. create table edu_student(
  5. student_id int auto_increment primary key,
  6. student_name varchar(64) not null comment '学生姓名',
  7. student_no varchar(20) not null comment '学号',
  8. gender char(1) null comment 'M 男 | F 女 | U 未填写',
  9. age tinyint null comment '年龄',
  10. major varchar(64) not null comment '专业',
  11. register_time datetime not null comment '入学时间',
  12. counselor varchar(64) not null comment '咨询师',
  13. class_name varchar(64) not null comment '班级',
  14. raw_add_time datetime not null default CURRENT_TIMESTAMP comment '记录添加时间',
  15. raw_update_time datetime not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '记录更新时间'
  16. )
  17. engine=innodb
  18. DEFAULT CHARSET = utf8
  19. COMMENT ='学生信息表';

关联关系存储

要理解数据库是二维表
一对多、多对一,将关联关系存在多的一方
多对多,将关联关系存成另一张中间表

数据库引擎选择innodb,使用业务无关的自增主键

MyISAM一旦出现系统宕机或者进程崩溃情况容易造成存储数据损坏。此外,频繁读写的InnoDB表,一定要使用具有自增/顺序特征的整型作为显式主键。MySQL :使用业务无关的自增主键,详见下文

控制单表数据量

单表记录控制在1000w行.(也可以考虑分区)

控制列数量

单表字段数上限控制在20到50之内.字段少而精可以提高并发,IO更高效 (优化InnoDB表BLOB列的存储效率)
原因是存储引擎的API工作时需要在服务器层和存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列,这个转换过程的代价是非常高的。如果列太多而实际使用的列又很少的话,有可能会导致CPU占用过高。

平衡范式与冗余

效率优先,提高性能. 适时牺牲范式增加冗余

禁止在数据库里存图片和文件

禁止在数据库中使用varbinaryblobtext存储图片和文件.

数据库完整性要求

不在数据库层面约束数据的完整性,数据的完整性由程序来保证.

字段选择合适的数据类型

IP字段

如果是使用的IPV4,则使用int存储不使用char(15).
在MySQL中提供了INER_ATONO()INET_NTOA()函数来对IP和数字之间进行转换. 前者提供IP到数字的转换后者提供数字到IP的转换.

  1. insert into table column(ipvalues(INET_ATONO('127.0.0.1')) ;

如业务需求需要存储IPV6,可采用varchar(40)类型.

手机字段

如果考虑到varchar占用空间大影响查询性能,请使用bigint来存储手机号码.

  • 不要使用int,因为int类型的最大长度不能超过11位
  • 如果手机号码中含有地区码,则用varchar

    enumsettinyint类型使用

    枚举类型可以使用ENUM,ENUM的内部存储机制是采用TINYINT或SMALLINT(并非CHAR/VARCHAR)。
    注意:ENUM类型扩展性较差,如果新增枚举值,需要修改表字段定义,而且在执行ddl时会对性能有影响

    金额字段

    对于金额字段,统一采用decimal(17,0)类型,金额以“分”为单位保存.

    时间字段

    时间字段优先考虑datetime.

    精确浮点数字段必须使用decimal替代float和double

    MySQL中的数值类型(不包括整型)IEEE754浮点数:单精度(float)、双精度(doublereal)、 定点数(decimalnumeric).
    floatdouble等非标准类型,在DB中保存的是近似值,而decimal则以字符串的形式保存数值

写代码的注意点

  1. 实体类与form对象必须区分开,字段不一定一致,考虑参数能少让用户传就少传(能够从系统获取,session中获取,其他字段解析出来比如身份证可以解析性别生日)
  2. 套路
    1. 打日志
    2. 参数校验,通用解析校验结果方法,ControllerBase
      1. <dependency>
      2. <groupId>org.springframework.boot</groupId>
      3. <artifactId>spring-boot-starter-validation</artifactId>
      4. </dependency>
      c. 调用service(业务校验),参数适配 BeanUtils
      d. 异常处理(通过全局异常处理器实现)
      e. 返回结果 Result(便捷方法)
      demo56.zip
      javamvc.zip

Restful风格

REST

  • 实体通过网址URL来表示: /product/1 @PathVariable
  • 通过HTTP协议的请求方法,表达对一个资源的操作
    • GET 查询 @GetMapping
    • POST 新增 @PostMapping
    • PUT 更新
    • DELETE 删除

2021年6月16日 Spring-Boot2 - 图1

http://kaelzhang81.github.io/2019/05/24/Restful-API%E8%AE%BE%E8%AE%A1%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/

传参

  1. formData传参
    1. <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    2. <script>
    3. $(function () {
    4. $.ajax({
    5. url:"/test1",
    6. type: 'post',
    7. dataType:'json',
    8. data:{
    9. 'username':'zhangsan',
    10. 'password':'abc123'
    11. },
    12. success:function(resp){
    13. console.log(resp)
    14. }
    15. });
    16. });
    17. </script>
    image.png
    后端用对象接受 ```java @PostMapping(“test1”) public Result doTest(TestForm testForm){
    1. log.info("TestForm:{}",testForm);
    2. return Result.success();
    }
  1. 2. payload 方式
  2. 前端:
  3. ```javascript
  4. <script>
  5. $(function () {
  6. $.ajax({
  7. url:"/test2",
  8. type: 'post',
  9. dataType:'json',
  10. data:JSON.stringify({
  11. 'username':'zhangsan',
  12. 'password':'abc123'
  13. }),
  14. contentType:'application/json;charset=utf-8',
  15. success:function(resp){
  16. console.log(resp)
  17. }
  18. });
  19. });
  20. </script>

image.png
后端接收

  1. @PostMapping("test2")
  2. public Result doTest2(@RequestBody TestForm testForm){
  3. log.info("TestForm:{}",testForm);
  4. return Result.success();
  5. }

注意点:

  1. @RequestBody 只能有一个
  2. Get/Delete请求不能用@RequestBody
  • @RequestBody
  • @RequestParam
  • @PathVaraible

    @SpringBootApplication

    核心注解 SpringBootConfiguration + EnableAutoConfiguration + ComponentScan ```java

@SpringBootConfiguration 标记为springboot配置类,即为spring的配置类,意味着可以在Application类里写@Bean注册bean @EnableAutoConfiguration 启动自动配置 @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) 包扫描 public @interface SpringBootApplication {

  1. @AliasFor(annotation = EnableAutoConfiguration.class)
  2. Class<?>[] exclude() default {};
  3. @AliasFor(annotation = EnableAutoConfiguration.class)
  4. String[] excludeName() default {};
  5. //指定扫描包路径,不指定时,默认为当前类所在的路径
  6. @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
  7. String[] scanBasePackages() default {};
  8. @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
  9. Class<?>[] scanBasePackageClasses() default {};
  10. @AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
  11. Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
  12. @AliasFor(annotation = Configuration.class)
  13. boolean proxyBeanMethods() default true;

}

  1. <a name="i4EFL"></a>
  2. # Spring-Boot的一些约定
  3. - 配置文件
  4. - XXXApplication必须直接放在根包下
  5. - resources
  6. - static 静态资源 前端渲染(浏览器执行)
  7. - template 模板 后端渲染(jvm)
  8. <a name="sxsgT"></a>
  9. # 集成mybatisplus
  10. 1. 导入依赖
  11. ```xml
  12. <dependency>
  13. <groupId>com.baomidou</groupId>
  14. <artifactId>mybatis-plus-boot-starter</artifactId>
  15. <version>3.2.0</version>
  16. </dependency>
  1. 修改配置

    1. mybatis-plus:
    2. type-aliases-package: com.woniuxy.boot.mybatisplusdemo.entity
    3. configuration:
    4. map-underscore-to-camel-case: true
    5. log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
    6. mapper-locations: classpath*:mappers/**/*.xml
  2. 加注解 @MapperScan

  3. 代码生成器

    1. 加依赖

      1. <!-- mybatis-plus代码生成器 -->
      2. <dependency>
      3. <groupId>com.baomidou</groupId>
      4. <artifactId>mybatis-plus-generator</artifactId>
      5. <version>3.2.0</version>
      6. <scope>test</scope>
      7. </dependency>
      8. <dependency>
      9. <groupId>org.apache.velocity</groupId>
      10. <artifactId>velocity-engine-core</artifactId>
      11. <version>2.1</version>
      12. <scope>test</scope>
      13. </dependency>
    2. 代码 ```java package com.woniuxy.boot.mybatisplusdemo;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;

import java.util.ArrayList; import java.util.List; import java.util.Scanner;

public class MybatisPlusGenerator {

  1. /**
  2. * <p>
  3. * 读取控制台内容
  4. * </p>
  5. */
  6. public static String scanner(String tip) {
  7. Scanner scanner = new Scanner(System.in);
  8. StringBuilder help = new StringBuilder();
  9. help.append("请输入" + tip + ":");
  10. System.out.println(help.toString());
  11. if (scanner.hasNext()) {
  12. String ipt = scanner.next();
  13. if (StringUtils.isNotEmpty(ipt)) {
  14. return ipt;
  15. }
  16. }
  17. throw new MybatisPlusException("请输入正确的" + tip + "!");
  18. }
  19. public static void main(String[] args) {
  20. // 代码生成器
  21. AutoGenerator mpg = new AutoGenerator();
  22. // 全局配置
  23. GlobalConfig gc = new GlobalConfig();
  24. String projectPath = System.getProperty("user.dir");
  25. gc.setOutputDir(projectPath + "/src/main/java");
  26. gc.setAuthor("Lucas");
  27. gc.setOpen(false);
  28. gc.setDateType(DateType.ONLY_DATE);
  29. // gc.setSwagger2(true); 实体属性 Swagger2 注解
  30. mpg.setGlobalConfig(gc);
  31. // 数据源配置
  32. DataSourceConfig dsc = new DataSourceConfig();
  33. //①数据源
  34. dsc.setUrl("jdbc:mysql://localhost:3306/edu_56?useUnicode=true&useSSL=false&characterEncoding=utf8");
  35. // dsc.setSchemaName("public");
  36. dsc.setDriverName("com.mysql.jdbc.Driver");
  37. dsc.setUsername("root");
  38. dsc.setPassword("root123");
  39. mpg.setDataSource(dsc);
  40. // 包配置
  41. PackageConfig pc = new PackageConfig();
  42. //② 包,留意parent设置为上一级,moduleName最后一级
  43. pc.setParent("com.woniuxy.boot");
  44. pc.setModuleName("mybatisplusdemo");
  45. pc.setController("controller");
  46. pc.setService("service");
  47. pc.setServiceImpl("service.impl");
  48. pc.setMapper("mapper");
  49. pc.setXml("mappers");
  50. pc.setEntity("entity");
  51. mpg.setPackageInfo(pc);
  52. // 自定义配置
  53. InjectionConfig cfg = new InjectionConfig() {
  54. @Override
  55. public void initMap() {
  56. // to do nothing
  57. }
  58. };
  59. // 如果模板引擎是 freemarker

// String templatePath = “/templates/mapper.xml.ftl”; // 如果模板引擎是 velocity String templatePath = “/templates/mapper.xml.vm”;

  1. // 自定义输出配置
  2. List<FileOutConfig> focList = new ArrayList<>();
  3. // 自定义配置会被优先输出
  4. focList.add(new FileOutConfig(templatePath) {
  5. @Override
  6. public String outputFile(TableInfo tableInfo) {
  7. // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
  8. return projectPath + "/src/main/resources/mappers" +
  9. "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
  10. }
  11. });
  12. /*
  13. cfg.setFileCreate(new IFileCreate() {
  14. @Override
  15. public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
  16. // 判断自定义文件夹是否需要创建
  17. checkDir("调用默认方法创建的目录");
  18. return false;
  19. }
  20. });
  21. */
  22. cfg.setFileOutConfigList(focList);
  23. mpg.setCfg(cfg);
  24. // 配置模板
  25. TemplateConfig templateConfig = new TemplateConfig();
  26. // 配置自定义输出模板
  27. //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别

// templateConfig.setEntity(“templates/entity2.java”); // templateConfig.setService(); // templateConfig.setController();

  1. templateConfig.setXml(null);
  2. mpg.setTemplate(templateConfig);
  3. // 策略配置
  4. StrategyConfig strategy = new StrategyConfig();
  5. strategy.setNaming(NamingStrategy.underline_to_camel);
  6. strategy.setColumnNaming(NamingStrategy.underline_to_camel);

// strategy.setSuperEntityClass(“com.baomidou.ant.common.BaseEntity”); strategy.setEntityLombokModel(true); strategy.setRestControllerStyle(true); // 公共父类 // strategy.setSuperControllerClass(“com.baomidou.ant.common.BaseController”); // 写于父类中的公共字段 // strategy.setSuperEntityColumns(“id”); strategy.setInclude(scanner(“表名,多个英文逗号分割”).split(“,”)); strategy.setControllerMappingHyphenStyle(true);

  1. //③ 表前缀
  2. strategy.setTablePrefix("edu");
  3. mpg.setStrategy(strategy);
  4. mpg.setTemplateEngine(new VelocityTemplateEngine());
  5. mpg.execute();
  6. }

}

  1. 1. 运行
  2. 1. 插件使用
  3. ```java
  4. package com.woniuxy.boot.mybatisplusdemo.config;
  5. import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
  6. import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
  7. import org.mybatis.spring.annotation.MapperScan;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.context.annotation.Configuration;
  10. @Configuration
  11. public class MybatisPlusConfig {
  12. // 旧版
  13. @Bean
  14. public PaginationInterceptor paginationInterceptor() {
  15. PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
  16. // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
  17. // paginationInterceptor.setOverflow(false);
  18. // 设置最大单页限制数量,默认 500 条,-1 不受限制
  19. // paginationInterceptor.setLimit(500);
  20. // 开启 count 的 join 优化,只针对部分 left join
  21. paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
  22. return paginationInterceptor;
  23. }
  24. }

分层架构

image.png

集成Thymeleaf

image.png
image.png
c.jsp就是一个后端模板
jsp因为本身的性能以及安全问题,已经被弃用,新兴的后端模板引擎替换了jsp
后端模板引擎

  • 老牌:Velocity、Freemarker
  • 新兴:ThymeleafMustache、Groovy

Thymeleaf核心理念:自然模板

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  4. </dependency>
  1. spring:
  2. datasource:
  3. driver-class-name: com.mysql.jdbc.Driver
  4. url: jdbc:mysql://localhost:3306/edu_56
  5. username: root
  6. password: root123
  7. thymeleaf:
  8. cache: false
  1. <!DOCTYPE html>
  2. <!--命名空间-->
  3. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>Title</title>
  7. </head>
  8. <body>
  9. hello thymeleaf
  10. <div>
  11. hello <span th:text="${username}">游客</span>
  12. <span th:if="${age >18}">
  13. 年轻小伙
  14. </span>
  15. <span th:unless="${age >18}">
  16. 小朋友
  17. </span>
  18. <ul>
  19. <li th:each="s : ${students}">
  20. <span th:text="${s}">小王</span>
  21. </li>
  22. </ul>
  23. </div>
  24. </body>
  25. </html>

https://www.cnblogs.com/jnba/p/10832878.html

日志框架

作业

需求分析
在线教育网站参考:https://demo.edu.roncoos.com/
介绍及技术架构:https://demo.edu.roncoos.com/blog/article/1266656581010952194
讲师协议,约定了分成:https://demo.edu.roncoos.com/apply

  1. 设计课程course、章chapter、*节lesson,产出建表sql
  2. 实现一个课程分页搜索,支持根据课程类别,收费方式进行搜索,spring-boot+mybatis-plus