什么是Spring
Spring是一个开源框架,2003年兴起的一个轻量级的Java开发框架,作者:Rod Johnson
Spring是如何简化Java开发的?
- 基于POJO的轻量级和最小侵入性编程
- 通过IOC,依赖注入(DI)和面向接口实现松耦合
- 基于切面(AOP)和惯例进行声明式编程
- 通过切面和模板减少样式代码
简而言之,他就是一个Javaweb的开发框架,和SpringMVC类似, 对比其他Javaweb框架的好处,官方说是简化开发,you can just run,能迅速开发web应用。
所有的技术框架的发展似乎都遵循了一条主线规律:从一个复杂应用场景衍生一种规范框架,人们只需要进行各种配置而不需要自己去实现它,这时候强大的配置功能成了优点;发展到一定程度之后,人们根据实际生产应用情况,选取其中实用功能和设计精华,重构出一些轻量级的框架;之后为了提高开发效率,嫌弃原先的各类配置过于麻烦,于是开始提倡约定大于配置,进而衍生出一些一站式的解决方案
这就是Java企业级应用:J2EE–>Spring—>SpringBoot的过程
简单来说就是SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,SpringBoot整合了所有的框架
SpringBoot主要优点:
- 起步依赖(简化依赖配置)
- 自动配置(简化常用工程相关配置)
- 开箱即用,提供各种默认配置来简化项目配置
- 辅助功能(内嵌式容器简化Web项目)
- 没有冗余代码生成和XML配置的要求
2、快速上手SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程
创建SpringBoot入门程序
-
创建新模块,选择Spring Initializr,并配置模块相关基础信息
-
选择当前模块需要使用的技术集
-
开发控制器类
// Rest模式 @RestController @RequestMapping("/hello") public class BookController { @GetMapping public String hello() { System.out.println("springboot is running..."); return "hello springboot."; } }
-
运行自动生成的Application类
注:基于idea开发SpringBoot程序需要确保联网且能够加载到程序框架结构
starter
- SpringBoot中常见项目名称,定义了当前项目使用的所有依赖坐标,以达到减少依赖配置的目的
parent
- 所有SpringBoot项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少依赖冲突的目的
- spring-boot-starter-parent各版本间存在着诸多坐标版本不同
在实际开发中,使用任意坐标时,仅书写GAV中的G和A,V由SpringBoot提供,除非SpringBoot未提供对应版本V
主启动类(xxxApplication)
- SpringBoot的引导类是Boot工程的执行入口,运行main方法就可以启动项目
- SpringBoot工程运行后初始化Spring容器,扫描引导类所在包加载bean
Boot内置了三款服务器分别是
tomcat(默认):apache出品,粉丝多,应用面广,负载了若干较重的组件
jetty:更轻量级,负载性能远不及tomcat
undertow:负载性能勉强跑赢tomcat
内嵌Tomcat工作原理是将Tomcat服务器作为对象运行,并将该对象交给Spring容器管理
2.1、基础配置SpringBoot默认配置文件application. properties,通过键值对配置对应属性
属性配置
# 服务器端口配置 server.port=80 # 关闭运行日志图标(banner) spring.main.banner-mode=off # 设置日志相关 logging.level.root=error
SpringBoot内置属性查询
配置文档
属性配置方式
SpringBoot提供了3种配置文件的格式
- properties (传统格式/默认格式)
- yml (主流格式)
- yaml
# application.properties server.port=80 # application.yml server: port: 81 # application.yaml server: port: 82
SpringBoot配置文件加载优先级
- application.properties(最高)
- application.yml
- application.yaml(最低)
不同配置文件中相同配置按照加载优先级相互覆盖,不同配置文件中不同配置全部保留
yaml
- YAML (YAML Ain’t Markup Language) ,一种数据序列化格式
- 优点
- 容易阅读
- 容易与脚本语言交互
- 以数据为核心,重数据轻格式
YAML文件扩展名
- .yml(主流)
- .yaml
核心规则:数据前面要加空格与冒号隔开
yaml数据读取
使用@Value读取单个数据,属性名引用方式: ${一级属性名.二级属性名…}
country: china server: port: 8081 user: name: xiaozhang hobby: - music - girl - swim # 对象数组缩略格式 user3: [ { name: liming,age: 25 },{ name: xiaolin,age: 26 } ]
// 读取yml数据中的单一数据 使用SPEL表达式取值 @Value(value = "${country}") private String country1; @Value(value = "${user.hobby[1]}") private String hooby1; @Value(value = "${user3[1].name}") private String name1; @Value(value = "${server.port}") private String port;
封装全部数据到Environment对象中
// 使用自动装配将所有的数据封装到一个对象的Environment中 @Autowired private Environment env; @GetMapping public String getAllBook() { // 取值 System.out.println(env.getProperty("server.port")); System.out.println(env.getProperty("user3[1].name")); return "SpringBoot is running..."; }
缺陷:把全部数据都封装了,有时只需要一部分数据
自定义对象封装指定数据
person: name: xiaozhao age: 22 gender: female birth: 2003-05-21 party: true hobby: [boy,music,housework]
// 1、定义数据模型封装yml文件中对应的数据 yml和实体类属性一一对应 // 2、定义为spring管控的bean @Component @Data // 3、指定加载的数据 @ConfigurationProperties(prefix = "person") public class Person { private String name; private Integer age; private String gender; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birth; private String party; private String[] hobby; }
注:封装类必须定义为Spring管理的bean,否则无法进行属性注入
3、整合第三方技术3.1、整合Mybatis
-
创建新模块,选择Spring初始化,并配置模块相关基础信息
-
选择当前模块需要使用的技术集(MyBatis、MySQL)
-
配置数据源参数
# 2、配置数据库相关信息 spring: datasource: username: root password: root url: jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai driver-class-name: com.mysql.cj.jdbc.Driver # 设置mybatis相关配置 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.zhang.pojo
-
编写实体类
-
定义数据层接口与映射配置
@Mapper //能够被容器识别到 public interface BookMapper { List
queryAllBook(); Book queryBookById(@Param("id") Integer id); Integer addBook(Book book); Integer delBook(@Param("id") Integer id); Integer modifyBook(Book book); } -
编写mapper.xml文件
select id, type, name, description from mybatis.tbl_book -
测试类中注入mapper接口,测试功能
@SpringBootTest class Springboot05MybatisApplicationTests { @Autowired private BookMapper bookMapper; @Test void contextLoads() { List
books = bookMapper.queryAllBook(); books.forEach(System.out::println); } }
-
手动添加SpringBoot整合Mybatis-Plus的坐标,可通过maven仓库获取
com.baomidou mybatis-plus-boot-starter3.4.2 -
编写实体类
-
定义数据层接口与映射配置,继承baseMapper
@Mapper public interface BookMapper extends baseMapper
{ //编写扩展方法 } 继承完baseMapper接口之后,无需编写mapper.xml文件,就拥有大部分 *** 作数据库的方法了
-
测试类中注入mapper接口,测试功能
@SpringBootTest class Springboot06MybatisPlusApplicationTests { @Autowired private BookMapper bookMapper; @Test void contextLoads() { System.out.println(bookMapper.selectById(1L)); } }
-
导入Druid对应的starter
com.alibaba druid-spring-boot-starter1.2.8 -
更改Druid的配置方式
spring: datasource: druid: username: root password: root url: jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver
-
方式同整合mybatis一致,只需要更改其数据源即可
-
测试类中注入mapper接口,测试功能
@SpringBootTest class Springboot07DruidApplicationTests { @Autowired private BookMapper bookMapper; @Test void contextLoads() { List
books = bookMapper.queryAllBook(); books.forEach(System.out::println); } }
4、基于SpringBoot整合SSMP通过整合以上三种技术,得出经验,在整合任何第三方技术时需
- 导入对应的starter
- 配置对应的设置或采用默认配置
4.1、环境搭建
-
创建新模块,选择Spring初始化,并配置模块相关基础信息
-
选择当前模块需要使用的技术集(SpringWeb、MySQL)
-
手动导入SpringBoot中不包含的坐标
com.baomidou mybatis-plus-boot-starter3.4.2 com.alibaba druid-spring-boot-starter1.2.8 -
修改配置文件为yml格式
-
设置端口为80方便访问
# 配置端口 server: port: 80
-
创建数据库表并添加数据
create database if not exists `ssMp`; use ssMp; create table if not exists `tb_book` ( `id` INT(10) auto_increment NOT NULL COMMENT '图书id', `type` VARCHAR(20) NOT NULL COMMENT '图书分类', `name` VARCHAR(50) NOT NULL COMMENT '图书名称', `description` VARCHAR(100) NOT NULL COMMENT '图书描述', PRIMARY KEY (`id`) ) ENGINE = INNODB DEFAULT CHARSET = utf8 # -------------------- INSERT INTO `tb_book` VALUES (1, '市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书'); INSERT INTO `tb_book` VALUES (2, '企业管理', '领导力', '高绩效团队管理法则不懂带团队你就自己累'); INSERT INTO `tb_book` VALUES (3, '企业管理', '高情商管理', '三分管人 七分做人'); INSERT INTO `tb_book` VALUES (4, '企业管理', '管理三要', '能识人 会用人 懂管人'); INSERT INTO `tb_book` VALUES (5, '经济学', '每个人的经济学', '做复杂世界的明白人'); INSERT INTO `tb_book` VALUES (6, '政治经济学', '政治经济学的任务', '揭示经济规律经济规律');
-
编写实体类
@Data @AllArgsConstructor @NoArgsConstructor public class Book implements Serializable{ private Integer id; private String type; private String name; private String description; }
-
配置yml文件
server: port: 80 # 配置druid数据源 spring: datasource: druid: username: root password: root url: jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver # 表名前缀 mybatis-plus: global-config: db-config: table-prefix: tb_ # 设置主键生成策略为数据库自增策略 id-type: auto # 开启MP日志(标准日志输出) configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
注:使用数据库自增策略必须给id设置为自动增长,否则报错
-
定义数据层接口与映射配置,继承baseMapper并指定泛型
@Mapper public interface BookMapper extends baseMapper
{ //编写扩展方法 } -
创建测试类并注入mapper接口,测试结果
@SpringBootTest public class BookMapperTestCase { @Autowired private BookMapper bookMapper; @Test public void testBookById() { Book book = bookMapper.selectById(6L); System.out.println(book); } }
-
添加分页功能
分页需要设定分页对象Ipage,其中封装了分页 *** 作中的所有数据
@Test void testPageBook() { //查询第二页,查询五条数据 IPage
page = new Page<>(2, 5); bookMapper.selectPage(page, null); System.out.println("当前页:" + page.getCurrent()); System.out.println("每页数据总量:" + page.getSize()); System.out.println("总记录数:" + page.getTotal()); // 多少页 = 总记录数 除以 每页数据总量 System.out.println("共多少页:" + page.getPages()); // 查询得到的数据 List records = page.getRecords(); records.forEach(System.out::println); } 分页 *** 作是在MP的常规 *** 作基础上增强得到(依赖MP分页拦截器),其内部是动态的拼写SQL语句,因此需要增强对应的功能,需要添加MP拦截器实现
@Configuration public class MPConfig { //配置分页插件 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { // 1、定义MP拦截器 MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 2、添加具体的拦截器 interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } }
-
按照条件查询
使用QueryWrapper对象封装查询条件,推荐使用LambdaQueryWrapper对象,所有查询 *** 作封装成方法调用
@Test void queryGetByCondition() { String name = "经济"; LambdaQueryWrapper4.3、编写Service相关代码(业务层)lqw = new LambdaQueryWrapper<>(); // 查询包含spring的数据 //if (name != null) lqw.like(Book::getName, name); // 动态条件拼接 lqw.like(!Strings.isNullOrEmpty(name), Book::getName, name); bookMapper.selectList(lqw); }
-
定义Service接口
public interface BookService { // 添加图书 Boolean save(Book book); // 修改图书 Boolean modify(Book book); // 删除图书 Boolean delete(Integer id); // 根据id查询图书 Book queryById(Integer id); // 查询全部图书 List
queryAll(); // 分页查询 IPage queryPage(int currentPage, int pageSize); } -
定义service对应实现类
// 定义为业务层的bean @Service public class BookServiceImpl implements BookService { @Autowired private BookMapper bookMapper; @Override public Boolean save(Book book) { return bookMapper.insert(book) > 0; } @Override public Boolean modify(Book book) { return bookMapper.updateById(book) > 0; } @Override public Boolean delete(Integer id) { return bookMapper.deleteById(id) > 0; } @Override public Book queryById(Integer id) { return bookMapper.selectById(id); } @Override public List
queryAll() { return bookMapper.selectList(null); } @Override public IPage queryPage(int currentPage, int pageSize) { IPage page = new Page<>(currentPage, pageSize); return bookMapper.selectPage(page, null); } } -
定义测试类测试相关功能
@SpringBootTest public class BookServiceTestCase { @Autowired private BookService bookService; @Test void testQueryById() { System.out.println(bookService.queryById(6)); } @Test void testPageBook() { //查询第一页,查询五条数据 IPage
page = bookService.queryPage(1, 5); // 查询得到的数据 List records = page.getRecords(); records.forEach(System.out::println); } } 注:Service接口名称尽量定义成业务名称,并与Mapper接口名称进行区分
-
简化通用业务层代码开发
MP提供有业务层通用接口ISerivce
与业务层通用实现类ServiceImpl 如果其中提供的方法不满足需要时,可以在通用类的基础上做功能重载或者功能追加(自定义需要的功能)
定义service接口
public interface IBookService extends IService
{ // 追加 *** 作与原始 *** 作通过名称区分,功能与之前类似 boolean addBook(Book book); boolean modifyBook(Book book); IPage queryPage(int currentPage, int pageSize); } 定义service对应实现类
@Service public class BookServiceImpl extends ServiceImpl
implements IBookService { @Autowired private BookMapper bookMapper; @Override public boolean addBook(Book book) { return bookMapper.insert(book) > 0; } @Override public boolean modifyBook(Book book) { return bookMapper.updateById(book) > 0; } @Override public IPage queryPage(int currentPage, int pageSize) { IPage page = new Page<>(currentPage, pageSize); bookMapper.selectPage(page, null); return page; } } 定义测试类测试相关功能
@SpringBootTest public class BookServiceTest { @Autowired private IBookService bookService; // 提供给我们查询全部的数据方法... @Test void testQueryAllBook() { List
books = bookService.list(); books.forEach(System.out::println); } }
4.4、编写controller相关代码(表现层)注:重载时不要覆盖原始 *** 作,避免原始提供的功能丢失
@RestController @RequestMapping("/books") public class BookController { @Autowired private IBookService bookService; @GetMapping public ListgetAll() { return bookService.list(); } // @RequestBody 实体数据 @PostMapping public Boolean save(@RequestBody Book book) { return bookService.addBook(book); } @PutMapping public Boolean modify(@RequestBody Book book) { return bookService.modifyBook(book); } // http:localhost/books/5 @DeleteMapping("{id}") public Boolean delete(@PathVariable Integer id) { return bookService.removeById(id); } // @PathVariable 路径变量 @GetMapping("{id}") public Book bookById(@PathVariable Integer id) { return bookService.getById(id); } @GetMapping("{currentPage}/{pageSize}") public IPage queryPage(@PathVariable int currentPage, @PathVariable int pageSize) { return bookService.queryPage(currentPage, pageSize); } }
使用postman测试接口
表现层数据一致性处理
设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议
@Data @NoArgsConstructor public class R { private Boolean flag; private Object data; public R(Boolean flag) { this.flag = flag; } public R(Boolean flag, Object data) { this.flag = flag; this.data = data; } }
表现层接口统一返回值类型结果
@RestController @RequestMapping("/books") public class BookControllerTwo { @Autowired private IBookService bookService; @GetMapping public R getAll() { return new R(true, bookService.list()); } // @RequestBody 实体数据 @PostMapping public R save(@RequestBody Book book) { //R r = new R(); //boolean data = bookService.save(book); //r.setData(data); return new R(bookService.addBook(book)); } @PutMapping public R modify(@RequestBody Book book) { return new R(bookService.modifyBook(book)); } // http:localhost/books/5 @DeleteMapping("{id}") public R delete(@PathVariable Integer id) { return new R(bookService.removeById(id)); } // @PathVariable 路径变量 @GetMapping("{id}") public R bookById(@PathVariable Integer id) { return new R(true, bookService.getById(id)); } @GetMapping("{currentPage}/{pageSize}") public R queryPage(@PathVariable int currentPage, @PathVariable int pageSize) { return new R(true, bookService.queryPage(currentPage, pageSize)); } }
4.5、前后端协议联调目的:设计统一的返回值结果类型便于前端开发读取数据
在前后端分离结构设计中页面归属于前端服务器
单体工程中页面应放置在resources目录下的static目录中
-
前端发送异步请求,调用后端接口(Retrieve)
// 列表 getAll() { // 使用axios发送异步请求 axios.get("/books").then((res) => { // console.log(res.data); this.dataList = res.data.data; }); }
-
添加 *** 作(Add)
//d出添加窗口 handleCreate() { this.dialogFormVisible = true; this.resetForm(); }, //重置表单 resetForm() { this.formData = {}; }, //添加 handleAdd() { axios.post("/books", this.formData).then((res) => { // 判断当前 *** 作是否成功 if (res.data.flag) { //1、关闭d层 this.dialogFormVisible = false; this.$message.success("添加成功"); } else { this.$message.error("添加失败"); } }).finally(() => { //2、重新加载数据 this.getAll(); }) },
-
删除 *** 作(Delete)
// 删除 handleDelete(row) { // console.log(row); //1、d出提示框 this.$/confirm/i("此 *** 作将永久删除当前信息,是否删除?", "温馨提示", {type: "info"}).then(() => { //2、删除 *** 作 axios.delete("/books/" + row.id).then((res) => { if (res.data.flag) { this.$message.success("删除成功"); } else { this.$message.error("删除失败"); } }).finally(() => { //重新加载数据 this.getAll(); }); }).catch(() => { //3、取消删除 this.$message.info("取消删除 *** 作"); }); },
-
修改 *** 作(Modify)
//d出编辑窗口 handleUpdate(row) { axios.get("/books/" + row.id).then((res) => { if (res.data.flag && res.data.data != null) { this.dialogFormVisible4Edit = true; this.formData = res.data.data; } else { this.$message.error("数据同步失败,自动刷新"); } }).finally(() => { // 重新加载数据 this.getAll(); }); },
-
消息一致性处理
// 定义SpringMvc异常处理器处理异常 @RestControllerAdvice public class ProjectExceptionAdvice { //拦截所有的异常信息 @ExceptionHandler(Exception.class) public R doException(Exception ex) { //记录日志 //通知运维 //通知开发 ex.printStackTrace(); return new R("服务器故障,请稍后再试!"); } }
修改表现层返回结果的模型类,封装出现异常后对应的信息
private String msg; //要显示的消息 public R(String msg) { this.flag = false; this.msg = msg; }
-
分页功能(Page)
替换查询全部功能为分页功能
//分页查询 getPage() { // 发送异步请求 axios.get("/books/" + this.pagination.currentPage + "/" + this.pagination.pageSize).then((res) => { // 加载分页数据 let data = res.data.data; this.pagination.currentPage = data.current; this.pagination.pageSize = data.size; this.pagination.total = data.total; this.dataList = data.records; }); },
分页页码值切换
//切换页码 handleCurrentChange(currentPage) { // 修改页码值为当前的页码值 this.pagination.currentPage = currentPage; // 执行查询 this.getPage(); },
-
条件查询(Condition)
查询条件数据封装
pagination: {//分页相关模型数据 currentPage: 1,//当前页码 pageSize: 10,//每页显示的记录数 total: 0,//总记录数 type: "", name: "", description: "" }
页面数据模型绑定(v-model进行绑定)
组织数据成为get请求发送的数据
//分页查询 getAll() { // 组织参数,拼接url请求地址 // console.log(this.pagination.type) let params = "?type=" + this.pagination.type + "&name=" + this.pagination.name + "&description=" + this.pagination.description; console.log(params); // /books/1/10?type=???&name=???&description=??? // 发送异步请求 axios.get("/books/" + this.pagination.currentPage + "/" + this.pagination.pageSize + params).then((res) => { let data = res.data.data; this.dataList = data.records; }); },
controller接收参数
@GetMapping("{currentPage}/{pageSize}") public R queryPage(@PathVariable int currentPage, @PathVariable int pageSize, Book book) { System.out.println("参数==>" + book); IPage
page = bookService.queryPage(currentPage, pageSize,book); return new R(true, page); }
业务层接口功能开发
IPagequeryPage(int currentPage, int pageSize, Book book); @Service public class BookServiceImpl extends ServiceImpl implements IBookService { @Override public IPage queryPage(int currentPage, int pageSize, Book book) { IPage page = new Page<>(currentPage, pageSize); LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); 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()); bookMapper.selectPage(page, lqw); return page; } }
至此,整合完毕,收工!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)