参考文章

  • 1.送给 Java 程序员的 Spring 学习指南 -InfoQ
  • 2.看起来很长但还是有用的Spring学习笔记 - 泊浮说 - SegmentFault 思否
  • 3.Spring常见问题总结(补充版)
  • 4.面试官:“谈谈Spring中都用到了那些设计模式?”。
  • 5、Spring实战第五版https://potoyang.gitbook.io/spring-in-action-v5/
  • 6、初始化Spring项目
  • 7、基于 Spring Boot 2.X 的 Spring Boot 深入学习项目。艿艿的 Spring Boot 系列
  • 8、SpringBoot官方API
  • 9、SpringBoot官方参考手册

    学习Spring之前具备的基础

    image.png

    Spring

    IOC思想

    概念

  • IOC(Inversion of Control) :程序将创建对象的权利交给框架。

  • 之前在开发过程中,对象实例的创建是由调用者管理的,代码如 下:
    • 1 浪费资源:StudentService调用方法时即会创建一个对象,如果不断调用方法则会创建大量StudentDao对象。
    • 2 代码耦合度高:假设随着开发,我们创建了StudentDao另一个 更加完善的实现类StudentDaoImpl2,如果在StudentService 中想使用StudentDaoImpl2,则必须修改源码。
  • IOC思想是将创建对象的权利交给框架,框架会帮助我们创建对象,分配对象的使用,控制权由程序代码转移到了框架中,控制权 发生了反转,这就是Spring的IOC思想。而IOC思想可以完美的解决 以上两个问题。

    容器接口

  • BeanFactory:BeanFactory是Spring容器中的顶层接口,它可 以对Bean对象进行管理。

  • ApplicationContext:ApplicationContext是BeanFactory的子 接口。它除了继承 BeanFactory的所有功能外,还添加了对国际 化、资源访问、事件传播等方面的良好支持。 ApplicationContext有以下三个常用容器实现类:

    • ClassPathXmlApplicationContext:该类可以从项目中读取配置文件
    • FileSystemXmlApplicationContext:该类从磁盘中读取配置文件
    • AnnotationConfigApplicationContext:使用该类不读取配置文件,而是会读取注解

      Spring Boot体系结构

      SpringBoot是Spring框架的模块。它用于轻松创建独立的生产级基于Spring的应用程序。它是在核心Spring框架的顶部开发的。
      SpringBoot遵循一个分层的体系结构,其中每一层都与它的直接下层或上层(层次结构)进行通信。
      之前了解 SpringBoot Architecture 后,我们必须了解其中的不同层和类。 SpringBoot中有四个层,如下所示:
  • 展示层

  • 业务层
  • 持久层
  • 数据库层

image.png

  • 展示层: 表示层负责处理HTTP请求,将JSON参数转换为对象,并对请求进行身份验证并将其传输到业务层。简而言之,它由视图即前端部分组成。
  • 业务层: 业务层处理所有业务逻辑 >。它由服务类组成,并使用数据访问层提供的服务。它还执行授权验证
  • 持久层: 持久层包含所有存储逻辑,并将业务对象与数据库行进行相互转换。
  • 数据库层: 在数据库层中, CRUD (创建,检索,更新,

image.png

  • 现在我们有验证器类,视图类和实用程序类。
  • Spring Boot使用类似于Spring MVC,Spring Data等的所有模块。SpringBoot的体系结构与Spring MVC的体系结构相同,不同之处在于: 不需要 DAO DAOImpl 类在Spring启动中。
  • 创建数据访问层并执行CRUD操作。
  • 客户端发出HTTP请求(PUT或GET)。请求发送到控制器,然后控制器映射该请求并进行处理。之后,如果需要,它将调用服务逻辑。
  • 在服务层中,所有业务逻辑都将执行。它对通过类映射到JPA的数据执行逻辑。
  • 如果没有发生错误,则会将JSP页面返回给用户。

    前后端分离项目

    Spring Boot前后端交互json

  • 一种是后端接口直接返回页面,后端页面渲染返回

  • 另外一种是返回JSON数据。微服务接口,前后端分离项目,手机app

    postman

    • 专业的接口测试工具去测试数据。
    • PostMan工具,
    • 作用是模拟浏览器请求,拼装参数和格式化json响应结果。

Postman能够发送任何类型的HTTP请求(GET, HEAD, POST,PUT..),附带任何数量的参数和HTTP headers。支持不同的认证机制(basic, digest,OAuth),接收到的响应语法高亮(HTML,JSON或XML)。
基于postman的RESTFUL接口测试

JSON解析-fastjson

pom.xml依赖

  1. <!-- fastjson坐标,处理json -->
  2. <dependency>
  3. <groupId>com.alibaba</groupId>
  4. <artifactId>fastjson</artifactId>
  5. <version>1.2.79</version>
  6. </dependency>

RESTful API

REST,表现层状态转移(representation state transfer)。 REST 是属于 WEB ⾃身的⼀种架构⻛格,是在 HTTP 1.1 规范下实现的。 简单来说,就是用URI表示资源,用HTTP方法(GET, POST, PUT, DELETE)表征对这些资源的操作。我们使用REST应用程序来开发和设计网络应用程序。它生成对数据执行CRUD操作的HTTP请求

  • Resource: 资源,即数据,存在互联网上的可被访问的实体
  • Representation: 数据的某种表现形式,如HTML, JSON。
  • State Transfer:状态变化,HTTP方法实现

参考文章
image.png
当然,现实世界中,可能并不一定严格地按照数据库操作的CRUD来理解API,比如,你有一个登录的API /login 你觉得这个API应该是 GET ,POST,PUT 还是 PATCH ?登录的时候用户需要输入用户名和密码,然后跟数据库里的对比(select操作)后反回一个登录的session token,然后这个token作为用户登录的状态令牌。如果按上面表格来说,应该是 select 操作进行 GET ,但是从语义上来说,登录并不是查询信息,应该是用户状态的更新或是新增操作(新增session),所以还是应该使用 POST,而 /logout 你可以使用 DELETE 。这里相说明一下,不要机械地通过数据库的CRUD来对应这些动词,很多时候,还是要分析一下业务语义。
陈浩RestAPI使用

前后端参数的传递

控制层(controller)

  1. @RequestBody注解通过MapJSONObject接收(太麻烦,既要从Map中取值,取完值后又要封装到Map
  2. @RequestParam注解接收**单个属性**(推荐)
  3. --语法:@RequestParam(value=”参数名”,required=”true/false”,defaultValue=””)
  4. 1value:参数名,
  5. 2required:是否包含该参数,默认为true,表示该请求路径中必须包含该参数,如果不包含就报错。 可以通过**@RequestParam(required = false)设置为非必传**

服务层(service)

  • service将控制层接受到的参数封装到map或javabean中再传递到dao层(即使是controller层用Map接收,service层中也要从Map中取值)
  • service中也可以直接将参数分别传递到dao层

    数据访问层(dao)

    通过@Param注解接收service层中的 (单个属性/Map/JavaBean)

    SpringBoot非web项目

    App项目启动类改造

    方法一:手动获取Spring容器中的Bean

    ```java /**
    • 创建非Web项目的第一种方式 */ @SpringBootApplication public class Application { public static void main(String[] args) {
             /**
      
      • SpringBoot程序启动后,返回值是ConfigurableApplicationContext,它也是一个Spring容器
      • 它其实相当于原来Spring容器中的ClasspathXmlApplicationContext */ //获取SpringBoot容器 ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args); //从Spring容器中获取指定的对象 HelloService helloService = (HelloService) applicationContext.getBean(“helloService”); //调用业务方法 String hi = helloService.getHi(); System.out.println(hi); }

}

<a name="a3emA"></a>
### 方法二:继承CommandLineRunner接口,使用自动注入特性
```java
/**
 * 创建非项目的第二种方式
 */
@SpringBootApplication
public class NotwebApplication implements CommandLineRunner{
    @Autowired
    private HelloService helloService;

    public static void main(String[] args) {
        SpringApplication.run(NotwebApplication.class, args);
    }

    @Override
    public void run(String[] args) throws Exception {
        String hi = helloService.getHi();
        System.out.println(hi);
    }
}

框架支持添加

  • 右键项目,Add Framework Support,选择Maven

    注解

    我们可以把@SpringBootApplication看作是@Configuration、@EnableAutoConfiguration、@ComponentScan注解的集合。 根据Spring Boot官网,这三个注解的作用是: @EnableAutoConfiguration:启用Spring Boot的自动配置机制。 @ComponentScan:扫描被@Component(@Service,@Controller)注解的bean,注解默认会扫描该类所在包下的所有类。 @Configuration:允许Spring上下文中注册额外的bean或导入其他配置类。
    2.@Autowired: 自动导入对象到类中,被注入进的类要被Spring容器管理。

    controller(@Controller默认多例)层

    @RestController和@RequestMapping使用@PathVariable:获取url中的数据@RequestParam :获取请求参数的值@GetMapping ,当然也有对应的Post等请求的简化写法

  • **@RequestMapping** :配置url映射

  • **@RestController**: @RestController注解是@Controller和@ResponseBody的合集,主要用于返回JSON数据或XML数据。
    • @Controller: 对应Spring MVC控制层,主要返回页面。修饰class,⽤来创建处理http请求的对象。
    • @ResponseBody ,它将方法返回值绑定到响应主体。它告诉Spring Boot Framework将返回的对象序列化为JSON和XML格式。

      @Component:

      通用注解,可标注任意类为Spring组件。如果一个Bean不知道属于哪层,可以使用@Component注解

      默认实例化的对象是单例,如果想声明成多例对象可以使用@Scope(“prototype”)

      @Service(默认单例): 对应服务层,主要涉及一些复杂的逻辑。

      Dao层

      1、@Repository(默认单例): 对应持久层即Dao层,主要用于数据库相关操作。

      2、Mybaties Annotation

      @Mapper// 标志为 Mybatis 的 Mapper

      @Select

      模糊查询符号:
      @Select(“ select from weather.user where user_name=**#{name}** “)
      @Select(“select
      from weather.user where user_name=**'${userName}'**“)

      @Results和@Result

      Results中可以包含多个Result注解。其中每个Result注解设置javaBean对象和数据库表映射关系。column数据库字段。property是Bean属性。(如果数据库与javaBean对象名字相同或着设置了自动转驼峰全局配置不用写)

      @Param (一个参数可以不用)

      如果你的映射器的方法需要多个参数, 这个注解可以被应用于映射器的方法 参数来给每个参数一个名字。否则,多 参数将会以它们的顺序位置来被命名 (不包括任何 RowBounds 参数) 比如。 #{param1} , #{param2} 等 , 这 是 默 认 的 。 使 用 @Param(“person”),参数应该被命名为 #{person}。
      @RequestBody

7.@Configuration: 一般用来声明配置类,可以使用@Component注解代替,不过用@Configuration注解声明配置类更加语义化。

APP层

Spring Boot应用打成WAR包,然后部署到外部容器运行,需要在应用中继承SpringBootServletInitializer类,然后重写config方法,将其指向应用启动类。

public class HwDataServerApplication extends SpringBootServletInitializer{
    public static void main(String[] args) {
        SpringApplication.run(HwDataServerApplication.class, args);
    }
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(HwDataServerApplication.class);
    }
}

系统实战

数据库设计

需求

学生端口:学生信息查询(密码、id)
教职工端口:学生列表查询,学生选课,老师成绩录入(录入成绩 同时更新到 学生的总学分),教师查询

实体

  • 学生(students):学号(s_id)、姓名(s_name)、班级(s_class)、性别(s_gender)、专业(s_major)、学分(credit_points)
  • 老师(teachers):教师编号(t_id)、姓名(t_name)、学院(t_school)
  • 课程(courses):课程编号(c_id)教师编号(t_id)、课程名称(c_name)、课程学分(credit_point)
  • 成绩(scores):学号(s_id)课程编号(c_id)、成绩(score)

    实体关系

  • 学生:课程 = m : n , 关系表:成绩

  • 课程:老师 = n : 1

    项目部署

    项目打包

    Maven项目

    Maven

    多环境配置

  • SpringBoot多环境配置,配置文件名为:application-环境名.yml

  • JDK运行SpringBoot的jar包时选择环境,命令为:java -jar jar包名 --spring.profiles.active=环境名

    Spring Boot配置热部署(IDEA2021.3 开发)

    热部署,就是在应用正在运行的时候升级软件,却不需要重新启动 应用。即修改完代码后不需要重启项目即可生效。在SpringBoot 中,可以使用DevTools工具实现热部署

    添加依赖

    <!-- 热部署工具 -->
    <dependency>
          <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <optional>true</optional>
    </dependency>
    

    IDEA配置

    File Setting ->Buile,Execution,Deployment-> Compiler ->勾选Build project automatically ->
    ->Advanced Settings ->勾选 Allow auto-make to start even if developed application is currently running->Apply

    第三方集成

    日志

    日志

    Mybaties框架

    导入依赖

    <!--mysql连接-->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <scope>runtime</scope>
          </dependency>
    <!--Mybatis集成-->
          <dependency>
              <groupId>org.mybatis.spring.boot</groupId>
              <artifactId>mybatis-spring-boot-starter</artifactId>
              <version>2.2.2</version>
          </dependency>
    

    邮件

    激活邮箱授权码

    163邮箱授权码:QZBGWKDQCCFXBBBP
    qq邮箱授权码:iwbdfjbeeqmdecbf

    导入依赖

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

    application.properties

    ##邮件发送需要的配置
    ## smtp服务主机 qq邮箱为smtp.qq.com
    spring.mail.host=smtp.163.com
    ## 服务协议
    spring.mail.protocol=smtp
    ## 编码集
    spring.mail.default-encoding=UTF-8
    ## 发送邮件的账户(注:可以是普通的手机号或登录账号,并非一定是邮箱)
    spring.mail.username=yazhai233
    ## 授权码
    spring.mail.password=QZBGWKDQCCFXBBBP
    spring.mail.test-connection=true
    ## 邮件发信人(即真实邮箱)
    spring.mail.properties.from=yazhai233@163.com
    ## 邮件标题(日志上传——天气监控,中文转Unicode码)
    spring.mail.properties.subject=\u65e5\u5fd7\u4e0a\u4f20\u2014\u2014\u5929\u6c14\u76d1\u63a7!!!
    spring.mail.properties.mail.smtp.auth=true
    ##启动TLS加密
    spring.mail.properties.mail.smtp.starttls.enable=true
    spring.mail.properties.mail.smtp.starttls.required=true
    ##设置超时时间
    spring.mail.properties.mail.smtp.connectiontimeout=5000
    spring.mail.properties.mail.smtp.timeout=3000
    spring.mail.properties.mail.smtp.writetimeout=5000
    

    spring-boot-starter-mailAPI使用

    JavaMailSenderImpl

  • 什么是JavaMailSender和JavaMailSenderImpl?
    JavaMailSender和JavaMailSenderImpl 是Spring官方提供的集成邮件服务的接口和实现类,以简单高效的设计著称,目前是Java后端发送邮件和集成邮件服务的主流工具。

  • 如何通过JavaMailSenderImpl发送邮件?
    非常简单,直接在业务类注入JavaMailSenderImpl并调用send方法发送邮件。其中简单邮件可以通过SimpleMailMessage来发送邮件,而复杂的邮件(例如添加附件)可以借助MimeMessageHelper来构建MimeMessage发送邮件。

    @Service
    public class MailService {
      @Resource
      JavaMailSenderImpl mailSender;
    
      public  void baseServer() {
          //创建简单邮件消息
          SimpleMailMessage message = new SimpleMailMessage();
          //获取全局配置文件中 spring.mail前缀的 properties
          String from = mailSender.getJavaMailProperties().getProperty("from");
          message.setSubject("邮件测试");
          message.setFrom(from);
          message.setTo("2087886525@qq.com");
          message.setSentDate(new Date());
          message.setText("hello world");
          //因为发送邮件是一种耗时的任务,从几秒到几分钟不等,因此,异步发送是保证页面能快速显示的必要措施
          //启动一个新线程来异步发送邮件
          new Thread(()->{
              mailSender.send(message);
          }).start();
      }
    

    为什么JavaMailSenderImpl 能够开箱即用 ?

    所谓开箱即用其实就是基于官方内置的自动配置,翻看源码可知晓邮件自动配置类(MailSenderPropertiesConfiguration) 为上下文提供了邮件服务实例(JavaMailSenderImpl)。具体源码如下:

@Configuration
@ConditionalOnProperty(prefix = "spring.mail", name = "host")
class MailSenderPropertiesConfiguration {
    private final MailProperties properties;
    MailSenderPropertiesConfiguration(MailProperties properties) {
        this.properties = properties;
    }
    @Bean
    @ConditionalOnMissingBean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl sender = new JavaMailSenderImpl();
        applyProperties(sender);
        return sender;
    }

其中MailProperties是关于邮件服务器的配置信息,具体源码如下:

@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private String host;
    private Integer port;
    private String username;
    private String password;
    private String protocol = "smtp";
    private Charset defaultEncoding = DEFAULT_CHARSET;
    private Map<String, String> properties = new HashMap<>();
}

导入本地jar包

jar包结构

## []表示directory
[org]
[META-INF]
[BOOT-INF]
    [lib](打包后,导入的jar所在目录)
    [classes]

引入本地jar包方法

  1. resources下创建文件夹jar用来存放本地jar包,并右键add as a library
  2. pom文件添加依赖

     <dependencies>
    <!--导入本地jar包-->
         <!--code.jar-->
         <dependency>
             <!--这三个属性自己定义即可-->
             <groupId>code.java</groupId>
             <artifactId>code-java</artifactId>
             <version>1.0</version>
             <!--jar包适用范围-->
             <scope>system</scope>
             <!--指定本地jar包路径-->
             <systemPath>${project.basedir}/src/main/resources/jar/code.jar</systemPath>
         </dependency>
         <!--导入本地jar包,End-->
     </dependencies>
    
     <build>
         <plugins>
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <!--mvn clean package打jar包之后,BOOT-INF\lib里面并不会出现本地jar包,
                 需要configuration属性配置 来将 scope为system的jar包 一并加载到打包到生成的BOOT-INF\lib目录中-->
                 <configuration>
                     <includeSystemScope>true</includeSystemScope>
                 </configuration>
             </plugin>
         </plugins>
     </build>
    

    读取配置文件

    //读取application.properties的属性
     @Value("${spring.mail.properties.from}")
     protected String from;
    

    疑难杂症

    1、POSTMAN测试工具

    ```java 遇到的错误:Content type ‘text/plain;charset=UTF-8’ not supported

解决方法:原因是数据传输格式错误。因为发送的数据是json格式的,而postman默认是text格式,所以改成选择json样式。 ``` image.png

2、Dao层的User和List等等对象都不用实例化

3、对象的属性名与表的属性名称需要逐一对应

法一:
全局配置(application.properties)下划线转驼峰配置
mybatis.configuration.map-underscore-to-camel-case=true
ep:user_name 对应 userName
法二:

@Results和@Result

Results中可以包含多个Result注解。其中每个Result注解设置javaBean对象和数据库表映射关系。column数据库字段。property是Bean属性。(如果数据库与javaBean对象名字相同或着设置了自动转驼峰全局配置不用写)

4、mysql增删查改返回值

5、mybatis多表查询返回结果集

ArrayList>

6、No bean named ‘xxx’ available异常,

大小写的问题
Springboot 在bean的名称返回时有个规则,当类名开头为连续至少两个大写字母时,会保留原有类名返回,当类名开头只有一个大写字母时,会返回小写开头的类名。例如类名为ExampleClass,在获取名称应该使用exampleClass,而如果类名为EXAMPLEClass,则获取名称时还是使用EXAMPLEClass。

7、完美修改项目名称

8、读取application.properties文件的中文乱码

原因:

spring boot项目默认的加载application.properties是通过字符集ISO-8859-1载入的

解决方法:将 中文转为Unicode码 再写进application.properties文件中