springboot基础篇

SpringBoot 基础篇

欢迎访问我的博客
02的博客 (lulyqqqq.github.io)

Restful风格

REST开发

REST,表现形式状态切换

  • 传统风格资源描述形式

    http://localhost/user/getById?id=1

    http://localhost/user/saveUser

  • REST风格描述形式

    http://localhost/user/1

    http://localhost/user

优点:

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
  • 书写简化

@RestController:将当前控制器类设置为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能

SpringMVC 常用注解 - 云+社区 - 腾讯云 (tencent.com)

将请求参数放入请求路径中,再由注解**@PathVariable**(“对应请求参数的名称”) 从而获得相对应的值,有多个参数就多个使用

RESTful API 一种流行的 API 设计风格

Restful原则:行为操作(资源的访问形式)

  • 增:post请求 @PostMapping
  • 删:delete请求 @DeleteMapping
  • 改:put请求 @PutMapping
  • 查:get请求 @GetMapping

一般来说请求路径不要出现动词

分页,排序等操作,不需要使用斜杠传参,一般传的参数不是数据库表的字段,可以不采用斜杠

@RequestBody @RequestParam @PathVariable

  • 区别
    • @RequestParam 用于接收url地址传参或者表单传参
    • @RequestBody用于接收json数据
    • @PathVariable用于接收路径参数,使用{参数名称}描述路径参数
  • 应用
    • 后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody 应用较广
    • 如果发送非json格式数据,选用@RequestParam接收请求参数
    • 采用RESTful进行开发,当参数较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值

springboot应用

springboot是简化Spring应用的初始搭建和开发过程 springboot简化了依赖的配置

Spring Boot Web 开发@Controller @RestController 使用教程 - fishpro - 博客园 (cnblogs.com)

将spring的配置文件和spring-mvc配置简化了

springboot的配置文件中 pom文件的继承父类的文件,父类的文件里规定了dependency坐标依赖的最好版本 自动配置

starter和parent

  • starter
    • springboot中常见的项目名称,定义了当前项目使用的所有依赖坐标,以达到减少依赖配置的目的
  • parent
    • 所有SpringBoot项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少依赖冲突的目的
    • spring-boot-starter-parent各版本间存在着诸多坐标版本不同
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.7</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
  • 实际开发 GAV(G:groupId A:artifactId V:version)
    • 使用任意坐标时,仅写GAV中的G和A,V由SpringBoot提供,除非SpringBoot为提供对应版本V
    • 如果发生坐标错误,则需要手动指定Version(但要小心版本冲突)

引导类

SpringBoot的引导类是Boot工厂的执行入口,通过mian方法就可以启动项目

加载spring容器 默认扫描对应包及其子包的内容 实例bean 放入spring容器

在这里插入图片描述

@SpringBootApplication
public class SpringbootQuickApplication {

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

}

内嵌tomcat(springboot支持切换web服务器)

在pom文件里引入的spring-boot-starter-web里自动加载tomcat服务器

tomcat的本质是用java语言编写的执行过程 现在SpringBoot将tomcat的执行过程封装成一个对象放入spring容器里,需要使用web程序直接引用tomcat对象,从而在tomcat上执行,所以SpringBoot不用配置tomcat服务器也可以使用tomcat

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-tomcat</artifactId>
  <version>2.6.7</version>
  <scope>compile</scope>
</dependency>

变更内嵌服务器:是将现有的服务器去除,添加全新的服务器

SpringBoot可以支持切换内置服务器有三个

  • tomcat(默认) apache出品,应用面广,负载若干较重的组件
  • jetty 更轻量级,可扩展性更高,负载性能远不及tomcat
  • undertow 负载性能勉强跑赢tomcat

配置文件

复制工程(快速新建模块)

  • 原则
    • 保留工程基础结构
    • 抹掉原始工程痕迹

在工作空间里复制对应工程,兵修改过程名称

删除与Idea相关的配置文件,仅保留src目录和pom文件

修改pom文件中的artifactId与新工程/模块名相同

保留备份后期使用

springboot配置文件(三种):

  • application.properties (主导)使用key-value的格式

server.port=80

  • application.yml(主流)

server:

​ port: 80

  • application.yaml(配置同上)

不同配置文件中相同配置按照加载优先级相互覆盖,不同配置文件中不同配置全部保留

yml配置文件里属性

使用@Value注解读取单个属性
@Value("${country}")
private String country1;
使用@Autowired获得全部属性
//自动装配 yml配置文件里的全部属性
@Autowired
private Environment env;
env.getProperty("user.name")

加载实体的get set方法使用lombok里注解**@Data自动加载,需要在pom文件加入lombok**的坐标

将一个类转换为bean用spring注解:@Component将其转换为bean并放入spring容器里

获得yml指定区域数据:@ConfigurationProperties(prefix=“字段名”)

springboot整合junit

测试类需要在启动类的包或子包中,可以省略启动类的设置,也就是省略calsses的设定

否则需要使用**@SpringBootTest(calsses = 启动类名)**注解来查找

SpringBoot整合junit相当于spring整合junit

spring整合junit是 使用@RunWith()+ContextConfiguration(calsses = 启动类名)

**而springboot是使用@SpringBootTest(calsses = 启动类名)**注解

@SpringBootTest(classes = Springboot03JunitApplication.class)
class Springboot03JunitApplicationTests {

    @Autowired
    private BookDao bookDao;

    @Test
    void contextLoads() {
        bookDao.save();
    }

}

springboot整合mybatis

在yml配置文件里添加配置数据库的相对应信息

# 配置相关信息
spring:
   datasource:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/test
      username: root
      password: nian0209

创建实体类domain和dao实现操作数据库的方法 注意:实体类名应该和数据库的字段名一致

@SpringBootTest
class Springboot04MybatisApplicationTests {

    //这里虽是接口的注入但实际注入的对象是实现类的对象
    @Autowired
    private BookDao bookDao;

    @Test
    void contextLoads() {
        System.out.println(bookDao.getById(2));
    }

}

至于在controller层上使用的service的接口而不是实现类

因为通过**@Autowired的对象是通过接口的方式会使用jdk的动态代理**,jdk的动态代理针对接口产生代理,动态的产生实现类的对象,在注入到spring容器里也是实现类的对象 这样使用jdk代理的方式动态的生成接口的实现类,还可以实现对实现类的增强从而做到增强类

一个接口里有多个实现类

Spring中如Service有多个实现类,它怎么知道该注入哪个ServiceImpl类?_Java知音_的博客-CSDN博客

@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常

@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用

@Autowired

@Qualifier(“personDaoBean”) 存在多个实例配合使用

在service层使用@Service(名称)来将实现方法带名称的注入到spring容器里

使用@Autowired自动注入,

@Qualifier(“beanId”):beanId是指对应实现类的类名称且字母开头小写

  • 方法一: Controller中注入service的时候使用**@Autowired**自动注入,@Qualifier("beanId")来指定注入哪一个。
  • 方法二: Controller中注入service的时候使用@Resource(type = 类名.class)来指定注入哪一个。
  • 方法三:
    • 每个service的impl都可以指定名称(使用@Service(“名称”)
    • Controller中注入service的时候使用名称来指定注入哪一个(使用@Resource(name="名称")

@Autowired注解的意思就是:

当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。

@Resource的作用相当于@Autowired

@Autowired和@Resource两个注解的区别:

1.@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了。

2.@Autowired默认按照byType(方法类型)方式进行bean匹配,@Resource默认按照byName(方法名称)方式进行bean匹配。

3.@Autowired默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false)

springboot整合MyBatis-Plus

  • MyBatis-plus与MyBatis区别
    • 导入坐标不同
    • 数据层实现简化

手动导入MP坐标

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>

springboot整合Druid

导入Druid对应的starter

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>

在yml配置文件中配置druid数据源

# Druid整合
spring:
   datasource:
      druid:
         driver-class-name: com.mysql.cj.jdbc.Driver
         url: jdbc:mysql://localhost:3306/test
         username: root
         password: nian0209

SSMP整合案例

基于springboot

  • 案列方案分析
    • 实体类开发—使用lombok快速制作实体类
    • Dao开发—整合MyBatisPlus,制作数据层测试类
    • Service开发—基于MyBatisPlus进行增量开发,制作业务层测试类
    • Controller开发—基于Restful开发,使用PostMan进行接口测试
    • Controller开发—前后端开发协议制作(前后端数据交换形式)
    • 页面开发—基于VUE+ElementUI制作,前后端联调,页面数据处理,页面消息处理
      • 列表,新增,修改,删除,分页,查询
    • 项目异常处理
    • 按条件查询—页面功能调整,Controller修正功能,Service修正功能

准备步骤

勾选springweb 和 mysql对应坐标

修改配置文件为yml格式并设置端口并设置自动增长的属性 开启日志

mybatis-plus:
  global-config:
    db-config:
#      设置id自增
      id-type: auto
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

数据库

分页

使用MP快速的查看分页的数据,但是需要指定spring拦截器 在使用语句前也需要传入分页对应的参数----(第几页,几条数据)

IPage page = new Page(1,3);
bookDao.selectPage(page,null);
 //打印当前页内数据
System.out.println(page.getRecords());
@Configuration
public class MPConfig {

    //使用拦截器创建分页
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //定义MP拦截器
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加具体的拦截器
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return  interceptor;
    }
}

条件查询

使用QueryWrapper则需要自己去写对应匹配查询的字段,使用LambdaQueryWrapper则直接get就行了

like方法里可以添加判断条件:不为空的时候才执行条件查询

//按条件查询
@Test
void testBy() {

    QueryWrapper<Book> queryWrapper = new QueryWrapper<>();
    queryWrapper.like(true,"name","学");
    bookDao.selectList(queryWrapper);

}
//按条件查询
@Test
void testBy2() {

    String name = null;
    LambdaQueryWrapper<Book> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.like(name!=null,Book::getName,name);
    bookDao.selectList(lambdaQueryWrapper);

}

业务层-快速开发

实现Service接口和实现类

使用MyBatisPlus提供业务层通用接口(IService)与业务层通用实现类(ServiceImpl<M,T>)

在通用类基础上做功能重载或追加

注意重载时不要覆盖原始操作,避免原始提供的功能丢失-----可以在方法名上添加@Override查看有无重名

public interface IBookService extends IService<Book> {
}
@Service
public class IBookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService {
}

表现层展示

接收参数:

实体数据:@RequestBody

路径变量:@PathVariable

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private IBookService bookService;
	//查
    @GetMapping
    public List<Book> getAll(){
        return bookService.list();
    }
	//增
    @PostMapping
    public Boolean save(@RequestBody Book book){
        return bookService.save(book);
    }
	//改
    @PutMapping
    public Boolean update(@RequestBody Book book){
        return bookService.modify(book);
    }
	//删
    @DeleteMapping("{id}")
    public Boolean delete(@PathVariable int id){
        return bookService.delete(id);
    }
	//查
    @GetMapping("{id}")
    public Book getById(@PathVariable int id){
        return bookService.getById(id);
    }
}

表现层信息一致性处理

设计表现层返回结果的模型类,用于后端和前端进行数据格式统一,也称为前后端数据协议

flag:代表查询是否成功

data:存放数据

同意表现层数据

@Data
public class R {
    private boolean flag;
    private Object data;
    R(){

    }
    public R(Boolean flag){
        this.flag =flag;
    }

    public R(Boolean flag,Object data){
        this.data = data;
        this.flag = flag;
    }
    
    public R(Boolean flag,String msg){
        this.flag = flag;
        this.msg = msg;
    }

    public R(String msg){
        this.flag = false;
        this.msg = msg;
    }
}

前后端 页面

前后端协议联调

  • 前后端分离结构设计在页面归属前端服务器
  • 单体工程页面在resoures目录下的static目录中(建议执行clean)

发送异步请求,调用后端接口

axios.get(“/books”).then((res)=>{

​ 数据连接

});

异常处理

自定义springmvc的异常处理类来处理异常 在类上添加@RestControllerAdvice定义restful风格异常处理类且返回的数据给前端也需要和

前后端数据协议一致

//作为springmvc的异常处理器
//@ControllerAdvice
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //拦截所有的异常信息
    @ExceptionHandler(Exception.class)
    public R doException(Exception ex){
        //记录日志
        //通知运维
        //通知开发
        ex.printStackTrace();
        return new R("服务器故障,请稍后再试!");
    }
}

条件查询

分页部分的条件查询是根据v-model动态模型,在分页的基础上动态的添加查询数据,一起传到后端

//分页查询
getAll() {
    //组织参数,拼接url请求地址
    // console.log(this.pagination.type);
    param = "?type="+this.pagination.type;
    param +="&name="+this.pagination.name;
    param +="&description="+this.pagination.description;
    // console.log(param);

    //发送异步请求
    axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize+param).then((res)=>{
        this.pagination.pageSize = res.data.data.size;
        this.pagination.currentPage = res.data.data.current;
        this.pagination.total = res.data.data.total;

        this.dataList = res.data.data.records;
    });
},

service层判断条件查询有无值

@Override
public IPage<Book> getPage(int currentPage, int pageSize, Book book) {
    LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
    lqw.like(Strings.isNotEmpty(book.getType()),Book::getType,book.getType());
    lqw.like(Strings.isNotEmpty(book.getName()),Book::getName,book.getName());
    lqw.like(Strings.isNotEmpty(book.getDescription()),Book::getDescription,book.getDescription());
    IPage page = new Page(currentPage,pageSize);
    bookDao.selectPage(page,lqw);
    return page;
}

elementUI

分页插件

分页bug:一页中只有一个数据的时候。删除这个数据后当前页不会有信息展示,例如:原来有三页,删除了一页中只有一个数据的时候,系统还是在查删除完了那页,所以不会显示数据

解决方法:一般是在后台判断当前页是不是比总页数大,为true则返回最大页数数据 -----------但这也还是有bug

较好的解决方法是直接返回第一页

根本:根据需求修改

<!--分页组件-->
<div class="pagination-container">

    <el-pagination
            class="pagiantion"

            @current-change="handleCurrentChange"

            :current-page="pagination.currentPage"

            :page-size="pagination.pageSize"

            layout="total, prev, pager, next, jumper"

            :total="pagination.total">

    </el-pagination>

</div>
    @GetMapping("{currentPage}/{pageSize}")
    public R getPage(@PathVariable int currentPage,@PathVariable int pageSize,Book book){
//        System.out.println("参数==>"+book);

        IPage<Book> page = bookService.getPage(currentPage, pageSize,book);
        //如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
        if( currentPage > page.getPages()){
            page = bookService.getPage((int)page.getPages(), pageSize,book);
        }
        return new R(true, page);
    }

注意事项

在对应的实体类中,如果数据库和实体类的字段是驼峰命名MP会将其转化为下划线形式,如果需要对应有三种办法

  • 将数据库表字段改为下划线形式

  • 在实体类字段上添加@tableFiled(“字段名”)

  • 在yml配置文件中的mybatis-pus添加

  • mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
        map-underscore-to-camel-case: false #关闭驼峰映射
    

实体类有主键的需要在实体类主键字段头添加@TableId(type = IdType.AUTO(自增长类型))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

02XD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值