Web开发SpringBoot SpringMVC Spring的学习笔记(包含开发常用工具类)

一.Spring SpringMVC SpringBoot

三者的联系

在这里插入图片描述

MVC是一种设计框架, 市面上也有很多其他的MVC web框架,但是SpringMVC是佼佼者

  • 总结: springboot是spring的升级, springMVC是一种MVC框架(MVC框架的作用看下图)
    在这里插入图片描述

在这里插入图片描述

SpringMVC工作原理

在这里插入图片描述
在这里插入图片描述
这里我的理解是handler可能是前端发ajax请求的那段代码?还是说是后端各种controller类和其RequestMapping(‘URL’)的一个集合?

  • 总结在这里插入图片描述
<!--MVC的包-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

相关参考文档如下:
MVC思想及SpringMVC设计理念
Spring MVC+ Spring + Mybatis “三大框架”介绍
SpringMVC—Handler到底是个什么?及流程详解

二.SpringBoot的学习

2.1 注解

本文基于这篇博客加上一些我个人的理解, 有一个很全的思维导图可以点击这个链接获取

2.1.1 SpringBoot的核心注解

本节几个注解会告诉我们SpringBoot是如何启动了, 具体可以看这个视频
@SpringBootApplication
通常用在启动类上,申明让spring boot自动给程序进行必要的配置,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

  1. @SpringBootConfiguration(补)

组合了 @Configuration 注解,实现配置文件的功能。

  1. @EnableAutoConfiguration(补)

打开自动配置的功能,也可以关闭某个自动配置的选项。

如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class });

  1. @ComponentScan
    Spring组件扫描功能,让spring Boot扫描到@Configuration和一些@Component(@Service, @Controller, @Repository都是基于@Component)标注的类并把它加入到程序上下文。在这里插入图片描述

2.1.2 配置导入注解(简化Spring配置写XML的痛苦)

@Configuration和@Bean(人为注册Spring 的 Bean)

为什么说是人为呢, 因为代码中有new的动作

  • @Configuration: 等同于spring的XML配置文件,使用Java代码可以检查类型安全。指出该类是 Bean 配置的信息源,相当于Spring的XML中的,一般加在主类上。
  • 相当于XML中的,放在方法的上面,而不是类,意思是产生一个bean,并交给spring管理;在这里插入图片描述
    为啥不直接将@Component或者基于@Component的@Service\@Controller\@Repository标注在该类上,直接交给SpringBoot管理呢?:
    因为许多第三方的库我们是没法直接去修改它的源代码的(即没法直接在第三方库的类上添加注解), 当我们需要使用第三方库又不想手动创建对象的时候(手动创建对象还要自己去释放)就可以:
    1. 手写一个配置类加上@Configuration
    2. 配置类中声明一个方法返回第三方库的对象即可,
    3. 最后给这个方法加上@Bean注解
@Import(补)

用来导入其他配置类;

@ImportResource(补)

用来加载xml配置文件;

@Autowired@Qualifier和 @Resource(name=“name”,type=“type”)(获取Bean)
  • @Autowired:自动导入依赖的bean,自动导入依赖的bean。byType方式(因此如果一个Service接口有两个实现类的时候,就必须使用@Resource了(支持byName))。把配置好的Bean拿来用,完成属性、方法的组装,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。当加上(required=false)时,就算找不到bean也不报错;
  • @Resource:没有括号内内容的话,默认byName,与@Autowired干类似的事;

在这里插入图片描述

@Inject(用的少,补)

等价于默认的@Autowired,只是没有required属性;

2.1.3业务层功能

@Component

泛指组件,当组件不好归类的时候(因为@Service@Controller@Repository都有明确的业务场景),我们可以使用这个注解进行标注;
在这里插入图片描述

@ResponseBody

@ResponseBody这个注解@RestController自带了一般不用写, 现在都是前后端分离的, 肯定直接用@RestController
表示该方法的返回结果直接写入HTTP response body中,一般在异步获取数据时使用,用于构建RESTful的api。在使用@RequestMapping后,返回值通常解析为跳转路径,加上@Responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@Responsebody后,会直接返回json数据。该注解一般会配合@RequestMapping一起使用;

@Controller @ResonanceBody和@RestController
  • Controller: 用于定义控制器类,在spring项目中由控制器负责将用户发来的URL请求转发到对应的服务接口(service层),一般这个注解在类中,通常方法需要配合注解@RequestMapping;
    • @Controller 用于定义一个控制器类,它通常用于处理用户的HTTP请求,并返回相应的视图(View)
    • @Controller类中的方法可以直接通过返回String跳转到JSP、HTML等模版页面。Spring会根据视图名解析出实际的视图,通常是一个HTML页面。
    • 在方法上加@ResponseBody注解,也可以返回实体对象的JSON数据。
    • 方法上的 @RequestMapping 或者其他映射注解(如 @GetMapping、@PostMapping 等)用于将特定的请求映射到相应的处理方法。
  • @RestController:用于标注控制层组件(如struts中的action),是@ResponseBody和@Controller的合集;
    • @RestController注解等价于@ResponseBody + @Controller。表示该控制器中的所有方法都返回数据而不是视图
    • 将每个方法的返回值直接作为 HTTP 响应的内容,而不经过视图解析器。@RestController类中的所有方法只能返回String、Object、Json等实体对象,不能跳转到模版页面。
    • @RestContoller类中相当于所有方法都自带@ResponseBody,会自动将方法的返回值转换为JSON格式的响应体返回给客户端。但也可以通过其他注解(如 @ResponseBody)来改变返回的数据格式。
    • @RestController如果想和@Controller一样跳转页面的话,可以使用ModelAndView进行封装。
      在这里插入图片描述
@Service

一般用于修饰service层的组件;在这里插入图片描述

@Repository(补)

用于标注数据访问组件,即DAO组件;

@RequestMapping

提供路由信息,负责URL到Controller中的具体函数的映射;

该注解包含以下6个属性:(常用value)

params:指定request中必须包含某些参数值是,才让该方法处理;
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求;
value:指定请求的实际地址,指定的地址可以是URI Template 模式;
method:指定请求的method类型, GET、POST、PUT、DELETE等;
consumes:指定处理请求的提交内容类型(Content-Type),如application/json,text/html;
produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。

@Value

注入 application.properties 或 application.yml 配置的属性的值;

@PathVariable

路径变量,参数与大括号里的名字一样要相同;

@Profiles

Spring Profiles 提供了一种隔离应用程序配置的方式,并让这些配置只能在特定的环境下生效。任何@Component或@Configuration都能被@Profile标记,从而限制加载它的时机;

@ConfigurationProperties

Spring Boot将尝试校验外部的配置,默认使用JSR-303(如果在classpath路径中)。你可以轻松的为你的@ConfigurationProperties 类添加JSR-303 javax.validation约束注解;

2.1.4 全局异常处理(补)

@ControllerAdvice

包含@Component,可以被扫描到,统一处理异常;

@ExceptionHandler(Exception.class)

2.2 IOC和AOP

IOC

IOC的实现方法通过三.手动实现一个简易版Spring框架这一节中的推荐视频我总结一下我的看法(我比较菜, 就通俗易懂点):我看了视频后, 发现IOC就是一个对象的ContainerMap这个Map填充的过程如下:

  1. Java通过包扫描(递归调用自己最终将该Spring项目下所有的类名得到一个集合)
  2. 遍历这个集合的类名, 通过反射判断其是否被添加Bean相关的注解标注, (添加Bean相关的注解有(Component\Configuration+Bean…)), 然后将被标注了这些类以Key-Value的形式放入container中
    • key就是注解中value的值
    • value就是这些类的对象的实例
AOP
  • 写在前面: AOP也是对面向对象编程的一个补充, 将每个重复的操作抽象出来成为一个切面对象
    本节主要介绍AOP应用场景, AOP的原理可以观看这个视频
  • AOP的应用场景:
    • 不想改变原来的业务代码且不想写重复的代码, 比如批量增加一个打日志的功能
    • AOP只能写非业务代码, 因为不同业务的代码不一样, 当然不能批量增加

案例: 看这个视频学的:给add\sub\div\mul每段业务代码中加入一个sout打日志的功能

如果自己给每个方法手写那肯定不行:
在这里插入图片描述
AOP的解决方法:

  • 1.编写注解类:LogAnnotation在这里插入图片描述

  • 2.编写切面对象类LogAspect
    在这里插入图片描述

  • 3.给需要打日志的方法加上@LogAnnotation注解在这里插入图片描述

三.手动实现一个简易版Spring框架(包含以前没有Spring时怎么发请求)

本节内容是看这个视频学习的, 本节以前没有Spring时怎么发请求这一部分内容略了, 大概就是通过MyServlet extend HttpServlet+ 写XML注明每个路径对应哪个Servlet实现的, 想了解的可以看上面那个视频
简易版Spring框架步骤:

  1. 加载配置文件, 得到第二步中包扫描的路径
  2. 包扫描所有的类(IO流+递归调用自己最终将该Spring项目下所有的类名存入一个集合中)
  3. 遍历这个集合的类名, 通过反射判断其是否被添加Bean相关的注解标注, (添加Bean相关的注解有(Component\Configuration+Bean…)), 然后将被标注了这些类以Key-Value的形式放入container中
    • key就是注解中value的值
    • value就是这些类的对象的实例
  4. 之前已经用一个MyDispatcherServlet拦截了所有的路径请求, 在这个大类中用一个handlerMapping存储下来所有请求的路径对应的类的方法名
    • Key是请求的路径
    • Value是该路径对应的类的方法名
      之后通过HttpRequest对象拿到对应的请求路径(URL)将这个URL和handlerMapping中的Key进行遍历比对:
      • 比对失败:返回404
      • 比对成功:取出对应的参数进行赋值, 然后反射调用对应Controller的方法

四.开发常用工具Lombok

4.0说在前面(如何快速使用Lombok)

  • 最简单的办法在maven中加入如下依赖
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    <scope>provided</scope>
</dependency>

在这里插入图片描述

  • 老版本的idea需要安装Lombok插件(否则写代码的时候会报错),并且打开设置中的enable annotation processing (否则idea不识别Lombok的注解)但是新版本(21开始吧)idea已经自带Lombok插件了;

    这里引出来一个问题:为什么要idea要装插件?
    因为idea本质上是一个可视化的编辑器, java编译器会根据Lombok的注解修改语法树,最终结果是被注解标记的java类生成的字节码文件中会包含Lombok生成的代码, 但是我们写代码的时候出于源码阶段还没编译呢, idea当然识别不出来Lombok的注解生成一些get set方法了

4.1了解Lombok

官网解释

Project Lombok is a java library that automatically plugs into your editor and build tools, spicing(香料,调味剂) up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.

提取关键词:Java 库、自动插件、提高效率、再也不编写get、equals等方法、使用注解

4.2Lombok的作用一:减少代码冗余

使用Lombok前:即使idea提供了快捷键cmd + n手动快捷生成get/set/equals/hashCode/toString方法,但表多了后还是很麻烦
在这里插入图片描述
使用后效果:加注解,减少代码冗余
在这里插入图片描述

4.3Lombok的作用二:方便打日志

日志和传统打印操作相比的好处是日志是可插拔的, 日后上线的时候可以在配置文件中动态的开关,但是sout的内容需要手动去一个个文件中寻找并删除

  • 小技巧@Sl4j打日志的时候不仅仅可以直接打印,还可以用如下这种占位符的方法打印变量
/**
     * 实现log4j的符号{}打印
     */
    @Test
    public void print2(){
 
        Person person1 = new Person("chen",123,"man");
        Person person2 = new Person("li",234,"women");
        System.out.println("=====================================================");
        //Person类用Lombok实现了toString()方法
        logger.info("This is a debug message,person1={},person2={}",person1,person2);
        System.out.println("=====================================================");
    }

在这里插入图片描述

4.4Lombok使用方法(各个注解作用)

  • @Data:生成该类的get/set/equals/hashCode/toString方法
  • @Sl4j:自动在该类中生成一个private Logger log = LoggerFactory.getLogger(this.getClass());即log对象, 我们可以通过log.info()\log.debug()\log.warning()…多种方式打日志
  • @Log:支持Log4j、Slf4j,日志功能, 具体Log4j没用过, 后面来补
  • @Accesors(chain = true):
    平常给一个对象赋值的时候我们需要person1.setAge(6);person1.setName(‘张三’); 使用这个注解后直接person1.setAge(6).setName('张三');进行链式编程;
  • @Builder:使用此注解进行对象的构建,函数式编程/链式编程,省去逐行字段set。
    CarLombok build = CarLombok.builder().id(1).type(“string”).price(88.8).level(‘a’).build();
    System.out.println(build.toString());
  • @AllArgsConstructor:生成该类的全部参数的构造函数, 不能生成部分参数的构造函数,如果想要生成部分参数的构造函数还是需要手动生成的;如果加上这个注解后相当于类中增加了一个全部参数的构造函数, 因此之前其他代码中用无参构造函数new的对象可能会报错, 我们还需要手动加上@NoArgsConstructor;即@AllArgsConstructor和@NoArgsConstructor一般一起使用 一般不用全部参数的构造方法, 我们习惯自己new完一个对象用set方法去赋值
  • @NoArgsConstructor:生成无参构造函数
  • @RequiredArgsConstructor:生成指定类型(final ,@NonNull)
  • @Getter和@Setter
  1. 可以为单个成员变量设置get方法
  2. 可以为所有成员变量设置get、set方法 。同时可以为某个成员变量设置其他权限(默认public)、或设置取消get/set方法
  3. 无法为static设置get/set方法,只为final类型设置get方法
  • @ToString等: 生成该类的get() set() tostring()方法

ToString只能加在类上,自动生成ToString方法,使用exclude排除多个字段,of必须包含哪些字段。

  • @EqualsAndHashCode

生成equals方法、canEqual(判断是否属于Car类)、hashCode方法。也可以进行相等比较的排除,指定。
例如:@EqualsAndHashCode(exclude = {“字段1”,“字段2”})

  • @NonNull
    可以加在成员变量前,也可以加在方法参数前。用来指定某个字段不能为空
  • val:类比JS中的val(弱引用类型),在编译阶段确定类型,简化操作
    使用 val map = new HashMap<String, String>();
    替换 Map<String, String> map = new HashMap<>();
  • @Cleanup:对资源流进行清理
    @Cleanup InputStream in = new FileInputStream(“filepath”);
    @Cleanup OutputStream out = new FileOutputStream(“filepath2”);

4.5Lombok原理

本节内容涉及java编译过程大家可以去了解一下, 同时还有一些注解相关的API;
学习注解就一定要学习java的反射, 有关注解和反射的知识可以查看我的另一篇博客

  • 没错, 上篇那个博客啥都没, hhh 待补!!!, 不过你可以查看下面这些内容
    下面的内容都是从这个视频学的, 这个视频后半部分还讲解了Spring是如何通过注解实现对象的代理的, 但是我只是知道它执行的顺序, 还没有彻底搞懂反射, 等我补完反射就来补SpringBoot项目的启动流程
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    为什么说注解也是一个类呢?在这里插入图片描述

Java规范:JSR 269(Java Specification Requests) 插件化注解处理API(Pluggable Annotation Processing API)
JDK6提供的特性,在 Javac编译期(SOURCE标识)利用注解,在字节码文件中生成get、set等方法
Java编译器执行过程:
在这里插入图片描述
查看编译后的字节码文件:在这里插入图片描述

  • 为什么说Lombok在源码阶段不生效, 他只是在java编译的时候在字节码文件中生成get\set方法
    以@Data为例,我们查看它的源码发现:
    在这里插入图片描述

JsonUtil

  1. Json <> Bean, 例如 将一个对象以string字符串的方式存储到redis的string中

BeanUtil

  1. Bean<>Map, 例如将一个对象以hashmap键值对的形式存储到redis的hash中
  2. JsonObject<>BeanUtil

StringUtil

  1. isNotBlank:判断一个String是否为空(空是指"“或” "这种)

代码习惯

  • 所有常量均定义宏
    写宏的时候 用下划线区分BEGIN_TIMESTAMP
  • 凡是自动拆箱都可能导致空指针(比如返回的是Boolean, 但是这是个null, 那么没办法拆箱成boolean了)
public boolean{
	Boolean success = ...
	//return success;
	return Boolean.TRUE.equals(success);
}
  • 少些嵌套
    if(success)
    {
    	try{}catch{}finally{}
    }
    ....
    改成
    if(!sucess)
    {
    	...
    }
    try{}catch{}finally{}
    
  • 注释在这里插入图片描述

idea快捷方式

soutv:打印一个value
fori:循环
cmd + n插入构造函数, 重写方法,实现方法等

debug技巧

在这里插入图片描述

设计接口

获得数据就get, 批量删除和增加的时候就post, del有的库不支持传json,因此批量删除直接写一个deleteMusic路径+post请求方式即可
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

设计DTO

设计一个表的时候不仅仅要带着id还要有对应的name,这样就不用封装DTO了
比如comment表中只有music_id,要musicName还要去用music_id查musicName,这样很麻烦

封装DTO的时候只有 想要的xxxDTO的属性小于 xxx的时候才要封装
不然直接在xxx的类中新增一个字段然后在上面 @TableField(exist = false)

多封装

在这里插入图片描述
在这里插入图片描述

MybatisPlus

为什么这里可以直接用save呢,他怎么知道我查的哪个表?
在这里插入图片描述
这是因为继承了mybatisplus中的ServiceImpl类,并指定了当前类用到的mapper接口UserMapper和对应的entity实体类user在这里插入图片描述

Mybatis-plus之QueryWrapper、QueryChainWrapper、LambdaQueryWrapper以及LambdaQueryChainWrapper用法

看这篇博客

回显主键id

mybatis的解决办法可以百度,大致是下面这种解决方法

 <!-- MySQL中获取主键并插入1 -->
    <insert id="insertUser" parameterType="user" keyProperty="userId" useGeneratedKeys="true">
        insert into USER(u_id, u_name, u_pwd) values(#{userId}, #{userName}, #{userPassword})
    </insert>

我自己使用mybatis-plus过程中发现save完一个实体对象后, 直接通过类似实体.getId()就可以获得主键id了

数据更新

遇到了一个小bug, 如果我们是直接更新的数据库的数据(这里的sonlistMusicDeleteIllegalMusic函数就是一个直接将数据库非法数据删掉的函数), 那么我们需要重新获得一次数据库数据, 不然还是拿着错误的数据去进行后续处理

记得删除
在这里插入图片描述

SpringBoot实践过程中的问题

PathVariable不能传中文参数问题

public Result addSongList(@PathVariable(“songlistname”) String songlistname, @PathVariable(“account”) String account)
不能传中文为PathVariable, 如果要传中文, 就最好使用queryParam

@RestContrlloer用成了Controller

Songlist忘了搞RestController了, 搞得Controller导致返回数据不是json而是一个页面重定向,因此一直404

Java基础

函数式编程:lambda表达式, stream流

函数式编程:lambda表达式, stream流
lambda表达式和stream流是函数式编程的一种表现, lambda表达式先出现的, stream流后出现的, stream流的出现也是得益于lambda表达式的

//用stream就不用再写一个for了
            List<String> musicIds = songListMusicList.stream()
                    .map(SonglistMusic::getMusicId)
                    .collect(Collectors.toList());

注解

注解
注解就是给一个东西打上标签, 方便程序在运行的时候拿到该标签下的类或者方法,字段等, 之后再通过反射进行一系列操作

map的应用场景

List songlistMusics = songlistMusicService.list();
我想统计这这个list中有多少songlistMusic对象有相同的musicId, 记录下对应的musicId和其对应的次数:

你可以使用 Java 的 Map 来统计 List 中相同 musicId 的数量,并记录对应的 musicId 和次数。下面是一个示例代码:

java
List songlistMusics = songlistMusicService.list();
Map<String, Integer> musicIdCountMap = new HashMap<>();

// 统计相同 musicId 的数量
for (SonglistMusic songlistMusic : songlistMusics) {
String musicId = songlistMusic.getMusicId();
Integer count = musicIdCountMap.getOrDefault(musicId, 0);
musicIdCountMap.put(musicId, count + 1);
}

// 输出每个 musicId 及其对应的次数
for (Map.Entry<String, Integer> entry : musicIdCountMap.entrySet()) {
String musicId = entry.getKey();
Integer count = entry.getValue();
System.out.println("musicId: " + musicId + ", count: " + count);
}
这段代码首先创建了一个空的 HashMap 对象 musicIdCountMap,用于存储 musicId 和对应的次数。然后使用 for-each 循环遍历 songlistMusics 列表,对每个 SonglistMusic 对象进行统计。如果某个 musicId 在 musicIdCountMap 中不存在,则将其初始次数设为 0;否则,获取当前次数并加1,再更新到 musicIdCountMap 中。

最后,使用 for-each 循环遍历 musicIdCountMap,输出每个 musicId 和对应的次数。

@PostMapping(“/updateSonglist”)
public Result updateSonglist(@RequestBody Songlist songlist)
{
return songlistService.updateSonglist(songlist);
}
居然也可以

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值