赞
踩
目录
2、整合mybatis(spring_04_mybatis)
- @RestController
- @RequestMapping("/books")
- public class BookController {
-
- @GetMapping
- public String getById(){
- System.out.println("springboot getById");
- return "springboot getById";
- }
-
- }
因为我们所创建的工程是使用别人的模板,有很多很多个包,有些包不需要使用,我们就可以将文件夹隐藏,从而更加简洁
. Idea中隐藏指定文件或指定类型文件
1. 【Files】→【Settings】
2. 【Editor】→【File Types】→【Ignored Files and Folders】
3. 输入要隐藏的名称,支持*号通配符
4. 回车确认添加
1.在工作空间赋值对应的工程,并修改工程名称。
2.只留下src 喝pox.xml文件
3.使用的时候,直接复制模板,将pox.xml文件打开将artifactId与新工程名字相同
4.在idea当中将工程导入进去,刷新maven
SpringBoot默认配置文件是application.properties
直接name=value的形式
- 例子::: #服务器的端口配置
- server.port=8081
-
- #设置日志相关
-
- logging.level.root=debug
- properties格式(默认配置文件格式)
- yml格式(主流)
- yaml格式
- application.properties(properties格式) ```properties server.port=80 ``` - application.yml(yml格式) ```YML server: port: 81 ``` - application.yaml(yaml格式) ```yaml server: port: 82 ```
application.properties > application.yml > application.yaml
**总结**
1. 配置文件间的加载优先级 properties(最高)> yml > yaml(最低)
2. 不同配置文件中相同配置按照加载优先级相互覆盖,不同配置文件中不同配置全部保留
*大小写敏感
*属性层级关系使用多行描述,每行结尾使用冒号结束
*使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)
*属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)
* #号 表示注释
2. 注意属性名冒号后面与数据之间有一个**空格**
3. 字面值、对象数据格式、数组数据格式
下面是yml数据格式
- 、、、application.yml
- users:
- - name: Tom
- age: 4
- - name: Jerry
- age: 5
-
- country: china
-
- 、、、java
-
- //读取单一数据
- @Value("${country}")
- private String country1;
-
- //读取对象数据
- @Value("${users[1].name}")
- private String name;
- @Value("${users[1].age}")
- private Integer age;
-
-
-
使用的也是${}
```YAML center: dataDir: D:/usr/local/fire/data tmpDir: D:/usr/local/fire/tmp logDir: D:/usr/local/fire/log msgDir: D:/usr/local/fire/msgDir ``` 如果你在书写yaml数据时,经常出现如下现象,比如很多个文件都具有相同的目录前缀 这个时候你可以使用引用格式来定义数据,其实就是搞了个变量名,然后引用变量了,格式如下: ```YAML baseDir: /usr/local/fire center: dataDir: ${baseDir}/data tmpDir: ${baseDir}/tmp logDir: ${baseDir}/log msgDir: ${baseDir}/msgDir ```
yml页面当中的数据可以看 5、yml数据读取
//如果一个一个获取数据太麻烦,可以直接将所有数据存储到Environment,然后通过它使用get方法拿数据,记得加上注释@Autowired(自动装配)
- 、、、、java
- @Autowired
- private Environment environment;
-
- @GetMapping
- public String getById(){
- System.out.println("age==>>"+ environment.getProperty("user[1].age"));
- return "springboot base configuration";
- }
@ConfigurationProperties(prefix = "datasource")
指定我们提取的是那一组数据
- 、、、yml
- #创建类,用于封装下面的数据
- #由spring帮我们去加载数据到对象当中,一定要告诉spring加载这组信息
- #使用时候从spring当中直接获取
- datasource:
- driver: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost/springboot
- username: root
- password: Xx20011128
-
- 、、、创建一个pojo类
-
- //1.定义数据模型封装yaml文件当中对应的数据
- //2.定义为spring管控的Bean
- @Component
- //3.指定需要加载的数据,将我们yml当中定义的名字放在这里提取
- @ConfigurationProperties(prefix = "datasource")
- public class MyDataSource {
-
- 、、、控制器当中
- @Autowired
- private MyDataSource myDataSource;
-
-
- @GetMapping
- public String getById(){
- System.out.println(myDataSource);
- return "springboot base configuration";
- }
这个就是我们测试类,如果测试类不在我们启动类的包或者子包当中,我们就添加classes来指定配置类
- ```JAVA
- //在注解@SpringBootTest中添加classes属性指定配置类
- @SpringBootTest(classes = Springboot04JunitApplication.class)
- class Springboot04JunitApplicationTests {
- //注入你要测试的对象
- @Autowired
- private BookDao bookDao;
- @Test
- void contextLoads() {
- //执行要测试的对象对应的方法
- bookDao.save();
- System.out.println("two...");
- }
- }
- ```
(1).将我们需要使用的jar加上
(2)yml配置文件
重点:这里面有一个问题,玩的端口号不设置称3306启动就会报错
- ```yaml
- #2.配置相关信息
- spring:
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/ssm_db
- username: root
- password: root
- ```
(3)pojo类
- public class Book {
- private Integer id;
- private String type;
- private String name;
- private String description;
(4)映射dao接口
这里面使用的mybatis注解配置,
-
- @Mapper
- public interface BookDao {
- @Select("select * from tbl_book where id = #{id} ")
- Book selectById(Integer id);
- }
(5)测试程序
- @SpringBootTest
- class Spring04MybatisApplicationTests {
- @Autowired
- private BookDao bookDao;
-
- @Test
- void contextLoads() {
- Book book = bookDao.selectById(1);
- System.out.println(book);
- }
-
- }
(1)添加依赖,在将module添加mysql包创建出来后,我们将mybatis-plus的jar依赖导入进去
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>3.5.2</version>
- </dependency>
(2)yml配置文件
#2.配置相关信息 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_tb?serverTimezone=UTC username: root password: Xx20011128 #设置所有表的通用前缀名称为tbl_,然后继承了BaseMapper的dao接口类, #就会再查询数据的时候加上前缀,因为我们数据库设置的是tbl_book mybatis-plus: global-config: db-config: table-prefix: tbl_
(3)创建pojo类
- public class Book {
- private Integer id;
- private String type;
- private String name;
- private String description;
(4)映射dao接口
最重要的就是这里 我们继承 BaseMapper<Book> ,指定表的类型,然后就会帮我们将数据库的一些增删改查的方法写出来
- //如果是整合mybatis-plus的话,我们这里的方法不需要写具体的方法操作了
- //mybatis-plus帮助我们写了
- @Mapper
- public interface BookDao extends BaseMapper<Book> {
- }
(5)测试方法
- @SpringBootTest
- class Spring05MybatisPlusApplicationTests {
-
- @Autowired
- private BookDao bookDao;
-
- @Test
- void contextLoads() {
- System.out.println(bookDao.selectById(3));
- }
-
- }
model哪里选择spring web ,mysql Driver
手动导入的有::前面不加mybatis是因为我们使用的mybatis-plus,所以不需要添加
- <!--mybatis-plus的jar包依赖-->这个永华简化Mapper操作
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>3.5.2</version>
- </dependency>
-
- <!--druid的jar依赖文件-->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.2.18</version>
- </dependency>
-
- <!--lombok-->这个给是方便我们实例化类
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
(1)开启日志文件
使用lombok的话,我们直接添加@Data属性
- //这个我们使用的是mybatis-plus,可以简化Mapper文件,
- //只需要继承BaseMapper<这里写我们pojo类>
- @Mapper
- public interface BookDao extends BaseMapper<Book> {
-
- }
分页查询获取查询数据,直接用创建的 IPage 对象使用get方法获取
- 测试包BookDaoTest下
-
-
- //分页查询,分页查询的话,它不能直接使用,我们需要在创捷一个MybatisPlus的拦截器,
- @Test
- void testGetPage(){
- // 其中selectPage方法需要传入一个封装分页数据的对象,
- //可以通过new的形式创建这个对象,当然这个对象也是MyBatisPlus提供的,别选错包了。
- //创建此对象时需要指定两个分页的基本数据
- IPage page = new Page(1, 5);
- bookDao.selectPage(page,null);
- //分页方法返回的就是page,我们要想获取查询数据,直接page。get的获取
- System.out.println(page.getCurrent());
-
- }
-
-
- 拦截器,我们创建config文件,专门存放配置类信息,在里面创建MP的配置配置类
-
- //这个是我们mybatisPlus的配置文件
- @Configuration//添加注解,让它成为配置文件
- public class MPConfig {
-
- 因为这个是配置文件,整体上还是spring的程序,
- 要将对象创建出来交给spring的ioc管理
- 配置拦截器,这个拦截器就是帮助我们动态的拼接limit语句,帮助我们完成分页查询
- @Bean
- public MybatisPlusInterceptor mybatisPlusInterceptor(){
- MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
- interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
- return interceptor;
- }
-
-
-
- }
这个记住一点,LambdaQueryWrapper是用来封装条件的对象,
QueryWrapper的话可能我们查询的条件name会打错,所以我们一般使用第一种情况
第一个是按条件分页查询,第二个是我们普通的按条件查询所有
- //按条件查询
- @Test
- void testGetBy(){
- String name = "spring";
- //这个是要传入值的对象,可以封装我们的条件
- LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
- //因为我们给条件传值的时候为null会将null作为值传入进去,所有LambdaQueryWrapper对象提供了这个值name!=null
- //将这个值传入进去就,如果为为空,我们就不将条件拼接进去
- lqw.like(name!=null,Book::getName,name);
- bookDao.selectList(lqw);
- }
- @SpringBootTest
- public class BookDaoTest {//测试我们dao下面的方法
- @Autowired
- private BookDao bookDao;
-
- @Test
- public void testSelectById(){
- System.out.println(bookDao.selectById(2));
- }
-
- @Test
- public void testSelectAll(){
- System.out.println(bookDao.selectList(null));
- }
-
- @Test
- public void testSave(){
- Book book = new Book();
- book.setName("测试1");
- book.setType("测试2");
- book.setDescription("测试3");
- bookDao.insert(book);
- }
-
- @Test
- void testDeleteById(){
- bookDao.deleteById(2);
- }
一般service接口的名称定义为业务名称,与dao当中的名称有所区分
-
-
- public interface BookService {
-
- Boolean save(Book book);
-
- Boolean delete(Integer id);
-
- Boolean update(Book book);
-
- Book getById(Integer id);
-
- List<Book> getAll();
-
- //分页查询,两个参数,当前页码,每页显示数目
- IPage<Book> getPage(int currentPage,int pageSize);
-
- }
-
- @Service
- public class BookServiceImpl implements BookService {
-
- @Autowired
- private BookDao bookDao;
-
- @Override
- public Boolean save(Book book) {
- int count = bookDao.insert(book);
- return count > 0;
- }
-
- @Override
- public Boolean delete(Integer id) {
- int count = bookDao.deleteById(id);
- return count > 0;
- }
-
- @Override
- public Boolean update(Book book) {
- int count = bookDao.updateById(book);
- return count > 0;
- }
-
- @Override
- public Book getById(Integer id) {
- return bookDao.selectById(id);
- }
-
- @Override
- public List<Book> getAll() {
- return bookDao.selectList(null);
- }
-
- //分页查询
- @Override
- public IPage<Book> getPage(int currentPage, int pageSize) {
- IPage page = new Page(currentPage,pageSize);
- return bookDao.selectPage(page,null);
- }
- }
直接写我们的业务层接口继承IService<T>,然后接口实现类继承业务通用实现类。
注意::要记住的就是ServiceImpl<M,T>一般就是ServiceImpl<BookDao,Book> ,M就是dao层的业务接口
- service接口
-
- public interface IBookService extends IService<Book> {
-
- boolean saveBook(Book book);
-
- boolean modify(Book book);
-
- boolean delete(Integer id);
-
- //分页
- IPage<Book> getPage(int currentPage, int pageSize);
-
- //分页加条件查询
- IPage<Book> getPage(int currentPage, int pageSize,Book book);
-
- }
-
- service接口的实现
-
- @Service//把这个纳入ioc容器管理
- public class IBookServiceImpl extends ServiceImpl<BookDao,Book> implements IBookService {
- //要记住的就是ServiceImpl<M,T>一般就是ServiceImpl<BookDao,Book> ,M就是dao层的业务接口
-
- @Autowired
- private BookDao bookDao;
-
- @Override
- public boolean saveBook(Book book) {
- return bookDao.insert(book)>0;
- }
-
- @Override
- public boolean modify(Book book) {
- int count = bookDao.updateById(book);
- return count >0;
- }
-
- @Override
- public boolean delete(Integer id) {
- int count = bookDao.deleteById(id);
- return count>0;
- }
-
- @Override
- public IPage<Book> getPage(int currentPage, int pageSize) {
- //如果只是分页查询这样就够了
- IPage<Book> page = new Page<Book>(currentPage,pageSize);
- return bookDao.selectPage(page,null);
- }
-
- //分页查询+条件查询
- @Override
- public IPage<Book> getPage(int currentPage, int pageSize,Book book) {
- IPage<Book> page = new Page<Book>(currentPage,pageSize);
- //这个是要传入值的对象,可以封装我们的条件
- LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
- //讲条件添加进去
- lqw.like(book.getType()!=null,Book::getType,book.getType());
- lqw.like(book.getName()!=null,Book::getName,book.getName());
- lqw.like(book.getDescription()!=null,Book::getDescription,book.getDescription());
- bookDao.selectPage(page,lqw);
- return page;
- }
-
- }
但是我们一般使用的是统一格式的方法,不然前端拿到的数据比较乱
- //@RestController
- @RequestMapping("/books")
- public class BookController2 {//表现层,这里的表现层数据没有统一格式
- //@Autowired
- private IBookService iBookService;
-
- @GetMapping
- public List<Book> GetAll(){
- return iBookService.list();
- }
-
- @GetMapping("/{id}")
- public Book GetById(@PathVariable("id") Integer id){
- return iBookService.getById(id);
- }
-
- @PostMapping
- public Boolean save(@RequestBody Book book){
- return iBookService.save(book);
- }
-
- @DeleteMapping("/{id}")
- public Boolean delete(@PathVariable("id") Integer id){
- return iBookService.removeById(id);
- }
-
- @PutMapping
- public Boolean update(@RequestBody Book book){
- return iBookService.modify(book);
- }
-
- //分页查询
- @GetMapping("/{current}/{size}")
- public IPage<Book> getPage(@PathVariable("current") int current,@PathVariable("size")int size){
- return iBookService.getPage(current,size,null);
- }
-
- }
10、控制表形层统一数据
使用这种格式 flag表示操作成功,false表示出现异常,date用来存储数据
在controller当中创建工具类utils,存放我们统一数据的类
- @Data//使用lombok构建实体类方法
- public class R {//表现层数据一致性处理
- private Boolean flag;
- private Object data;
- private String msg;
-
- public R(){}
- public R(Boolean flag){
- this.flag=flag;
- }
-
- public R(Boolean flag, Object data) {
- this.flag = flag;
- this.data = data;
- }
-
-
- public R(Boolean flag, Object data, String msg) {
- this.flag = flag;
- this.data = data;
- this.msg = msg;
- }
- }
控制器业务层代码,使用统一格式的方法
-
- @RestController
- @RequestMapping("/books")
- public class BookController {//表现层,这里的数据统一了格式
- @Autowired
- private IBookService iBookService;
-
- @GetMapping
- public R GetAll(){
- return new R(true,iBookService.list());
- }
-
- @GetMapping("/{id}")
- public R GetById(@PathVariable("id") Integer id){
- return new R(true,iBookService.getById(id));
- }
-
- @PostMapping
- public R save(@RequestBody Book book) throws IOException {
- //return new R(iBookService.saveBook(book));
- //这里模拟一个异常操作,当添加的数据name=123的时候报错
- if(book.getName().equals("123")){
- throw new IOException();
- }
- boolean flag = iBookService.saveBook(book);
- return new R(flag,null,flag ? "添加成功o.O":"添加失败O.o");
- }
-
- @DeleteMapping("/{id}")
- public R delete(@PathVariable("id") Integer id){
- return new R(iBookService.delete(id));
- }
-
- @PutMapping
- public R update(@RequestBody Book book){
- return new R(iBookService.modify(book));
- }
-
- //分页查询,这里将book作为提交查询数据一起传输过去
- @GetMapping("/{currentPage}/{pageSize}")
- public R getPage(@PathVariable("currentPage") int currentPage,@PathVariable("pageSize")int pageSize,Book book){
-
-
- IPage<Book> page = iBookService.getPage(currentPage, pageSize,book);
- //解决分页功能bug
- //如果当前的页码值大于最大页码值,那么就应该把最大页码之赋值给最当前页码值
- if(currentPage>=page.getPages())
- page=iBookService.getPage((int) page.getPages(), pageSize,book);
-
- return new R(true,page);
- }
-
- }
uils包下创建处理异常的类ProjectException,如果出现异常的话,直接返回数据,msg里面存储的状态为数据出错
- @RestControllerAdvice
- //springmvc的异常处理器
- public class ProjectException {
-
- @ExceptionHandler(Exception.class)
- public R doOrderException(Exception ex){
- //出现异常可以写记录日志啊,发消息给运维啊,发邮件给开发人员啊等等
- ex.printStackTrace();
- return new R(false,null,"系统错误o.O");
- }
- }
这里,我直接导入老师的前端资源,然后跟着配套写。
写的话先找到页面模块在哪里,跟着点击事件设置的下一步操作去写
- <!DOCTYPE html>
-
- <html>
-
- <head>
-
- <!-- 页面meta -->
-
- <meta charset="utf-8">
-
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
-
- <title>基于SpringBoot整合SSM案例</title>
-
- <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
-
- <!-- 引入样式 -->
-
- <link rel="stylesheet" href="../plugins/elementui/index.css">
-
- <link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css">
-
- <link rel="stylesheet" href="../css/style.css">
-
- </head>
-
- <body class="hold-transition">
-
- <div id="app">
-
- <div class="content-header">
-
- <h1>图书管理</h1>
-
- </div>
-
- <div class="app-container">
-
- <div class="box">
-
- <div class="filter-container">
- <el-input placeholder="图书类别" v-model="pagination.type" style="width: 200px;" class="filter-item"></el-input>
- <el-input placeholder="图书名称" v-model="pagination.name" style="width: 200px;" class="filter-item"></el-input>
- <el-input placeholder="图书描述" v-model="pagination.description" style="width: 200px;" class="filter-item"></el-input>
- <el-button @click="getAll()" class="dalfBut">查询</el-button>
- <el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
- </div>
-
- <el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row>
-
- <el-table-column type="index" align="center" label="序号"></el-table-column>
-
- <el-table-column prop="type" label="图书类别" align="center"></el-table-column>
-
- <el-table-column prop="name" label="图书名称" align="center"></el-table-column>
-
- <el-table-column prop="description" label="描述" align="center"></el-table-column>
-
- <el-table-column label="操作" align="center">
-
- <template slot-scope="scope">
-
- <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
-
- <el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
-
- </template>
-
- </el-table-column>
-
- </el-table>
-
- <!--分页组件-->
- <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>
-
- <!-- 新增标签弹层 -->
-
- <div class="add-form">
-
- <el-dialog title="新增图书" :visible.sync="dialogFormVisible">
-
- <el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right" label-width="100px">
-
- <el-row>
-
- <el-col :span="12">
-
- <el-form-item label="图书类别" prop="type">
-
- <el-input v-model="formData.type"/>
-
- </el-form-item>
-
- </el-col>
-
- <el-col :span="12">
-
- <el-form-item label="图书名称" prop="name">
-
- <el-input v-model="formData.name"/>
-
- </el-form-item>
-
- </el-col>
-
- </el-row>
-
-
- <el-row>
-
- <el-col :span="24">
-
- <el-form-item label="描述">
-
- <el-input v-model="formData.description" type="textarea"></el-input>
-
- </el-form-item>
-
- </el-col>
-
- </el-row>
-
- </el-form>
-
- <div slot="footer" class="dialog-footer">
-
- <el-button @click="cancel()">取消</el-button>
-
- <el-button type="primary" @click="handleAdd()">确定</el-button>
-
- </div>
-
- </el-dialog>
-
- </div>
-
- <!-- 编辑标签弹层 -->
-
- <div class="add-form">
-
- <el-dialog title="编辑检查项" :visible.sync="dialogFormVisible4Edit">
-
- <el-form ref="dataEditForm" :model="formData" :rules="rules" label-position="right" label-width="100px">
-
- <el-row>
-
- <el-col :span="12">
-
- <el-form-item label="图书类别" prop="type">
-
- <el-input v-model="formData.type"/>
-
- </el-form-item>
-
- </el-col>
-
- <el-col :span="12">
-
- <el-form-item label="图书名称" prop="name">
-
- <el-input v-model="formData.name"/>
-
- </el-form-item>
-
- </el-col>
-
- </el-row>
-
- <el-row>
-
- <el-col :span="24">
-
- <el-form-item label="描述">
-
- <el-input v-model="formData.description" type="textarea"></el-input>
-
- </el-form-item>
-
- </el-col>
-
- </el-row>
-
- </el-form>
-
- <div slot="footer" class="dialog-footer">
-
- <el-button @click="updateCancel()">取消</el-button>
-
- <el-button type="primary" @click="handleEdit()">确定</el-button>
-
- </div>
-
- </el-dialog>
-
- </div>
-
- </div>
-
- </div>
-
- </div>
-
- </body>
-
- <!-- 引入组件库 -->
-
- <script src="../js/vue.js"></script>
-
- <script src="../plugins/elementui/index.js"></script>
-
- <script type="text/javascript" src="../js/jquery.min.js"></script>
-
- <script src="../js/axios-0.18.0.js"></script>
-
- <script>
- var vue = new Vue({
- el: '#app',
- data:{
- dataList: [],//当前页要展示的列表数据
- dialogFormVisible: false,//添加表单是否可见
- dialogFormVisible4Edit:false,//编辑表单是否可见
- formData: {},//表单数据
- rules: {//校验规则
- type: [{ required: true, message: '图书类别为必填项', trigger: 'blur' }],
- name: [{ required: true, message: '图书名称为必填项', trigger: 'blur' }]
- },
- pagination: {//分页相关模型数据
- currentPage: 1,//当前页码
- pageSize:10,//每页显示的记录数
- total:0, //总记录数
- type:"", //条件查询数据
- name:"",
- description:""
- }
- },
-
- //钩子函数,VUE对象初始化完成后自动执行
- created() {
- //调用查询全部数据
- this.getAll();
- },
-
- methods: {
- //列表
- /* getAll() {
- //发送异步请求
- axios.get("/books").then((res)=>{
- this.dataList=res.data.data; //第一个data是拿到我们后端R表现层数据一致性处理的数据,第二个data是拿到r里面的数据
- })
- },*/
-
- getAll(){
- //条件查询数据,因为是get请求,我们需要做字符串的拼接
- param = "?query";
- param += "&type=" + this.pagination.type;
- param += "&name=" + this.pagination.name;
- param += "&description=" + this.pagination.description;
-
- //分页查询
- axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize + param).then((res)=>{
- this.dataList=res.data.data.records; //将查询到的数据给到表单数据存储当中
- //下面的是分页查询的页数,多少条,一共多少条
- this.pagination.currentPage=res.data.data.current;
- this.pagination.pageSize=res.data.data.size;
- this.pagination.total=res.data.data.total;
- })
- },
-
- //切换页码
- handleCurrentChange(currentPage) {
- //修改页码值为当前选中的页码值
- this.pagination.currentPage=currentPage;
- //修改页码后执行查询
- this.getAll();
- },
-
-
- //弹出添加窗口
- handleCreate() {
- //因为我们将添加表单设置为不可见,所以这里设置点击新建我们将弹窗改为true,让它弹出来
- this.dialogFormVisible=true;
- //一般清空数据设置在打开弹窗最为妥当
- this.resetForm();
- },
-
- //重置表单
- resetForm() {
- //将添加弹窗数据清空
- this.formData={};
- },
-
- //添加
- handleAdd () {
- //这个this.formData就是将我们弹出的添加窗口当中的数据添加打包传参
- //如果不添加操作失败,我们就不关闭弹窗
- axios.post("/books",this.formData).then((res)=>{
- if(res.data.flag){
- //1.操作成功,将弹窗关闭
- this.dialogFormVisible=false;
- this.$message.success(res.data.msg);
- }else {
- this.$message.error(res.data.msg);
- }
-
- }).finally(()=>{
- //2.添加了数据,重新刷新页面
- this.getAll();
- })
-
- },
-
- //添加弹窗取消
- cancel(){
- this.dialogFormVisible=false;//关闭添加创库弹窗
- this.$message.info("您取消了当前操作")
- },
-
- // 删除
- handleDelete(row) {
- //删除操作我们得设置一个提醒,万一用户手抖点错了就恢复不了,所以设置一个弹窗
- this.$confirm("此操作将会删除当前数据,是否继续","删除弹窗提示",{type:"info"}).then(()=>{
- //弹窗点击确定
- axios.delete("/books/"+row.id).then((res)=>{
- //判断是否删除成功
- if(res.data.flag){
- this.$message.success("删除成功")
- }else {
- this.$message.error("删除失败")
- }
- }).finally(()=>{
- //不管成功与否,都重新刷新页面,调用查询所有
- this.getAll();
- });
- }).catch(()=>{
- //弹窗点击取消
- this.$message.info("您取消了删除操作");
- });
-
-
- },
-
- //弹出编辑窗口
- handleUpdate(row) {
- //将我们编辑的哪一个数据查询编辑窗口表单当中
- axios.get("/books/"+row.id).then((res)=>{
- //出现1异常的情况
- if(res.data.flag && res.data.data!=null){
- this.formData=res.data.data
- //将编辑窗口改为true
- this.dialogFormVisible4Edit=true;
- }else{
- this.$message.error("数据同步失败,自动刷新");
- }
- }).finally(()=>{
- this.getAll();
- })
- },
-
- //修改
- handleEdit() {
- axios.put("/books",this.formData).then((res)=>{
- //判断是否操作成功
- if(res.data.flag){
- this.$message.success("操作成功");
- this.dialogFormVisible4Edit=false;
- }else{
- this.$message.error("操作失败");
- }
- }).finally(()=>{
- this.getAll();
- })
- },
-
- //编辑弹窗取消
- updateCancel(){
- this.dialogFormVisible4Edit=false;//关闭添加创库弹窗
- this.$message.info("您取消了当前操作")
- },
-
-
-
- }
- })
-
- </script>
-
- </html>
运行项目:java后面那个就是打包后的文件名字
下面的是我们检查端口的操作::
(1)一级::在我们编程的resources当中的:application.xml是给我们程序员用的
(2)二级:: 在编程的resources当中创建config包下的application.yml是给项目经理用的,而皮质等级高于前面
(3)三级::打包后的jar文件同级目录下的application.yml,
(4)四级::打包后的jar文件同级目录下的config,config包里面的application
等级越高,优先级越高,相同配置会覆盖前面的配置,不同的配置,会联合一起使用
这个是根据名字,也可以根据路径 --spring.config.location=classpath:/ebank.yml
yml文件当中,不同的环境用 --- 分隔开
- #应用环境,当前在使用的环境
- spring:
- profiles:
- active: dev
-
- #设置环境
- ---
- #生产环境
- spring:
- profiles: pro
- server:
- port: 80
- ---
- #开发环境
- spring:
- profiles: dev
- server:
- port: 81
-
- ---
- #测试环境
- spring:
- profiles: test
- server:
- port: 82
第二种方式
include的话,我们的主配置文件会在最后加载,而group的话就是先加载主配置文件,再加载指定的附属配置文件
pox.xml文件当中的配置
- **maven中设置多环境(使用属性方式区分环境)**
-
- ```xml
- <profiles>
- <profile>
- <id>env_dev</id>
- <properties>
- <profile.active>dev</profile.active>
- </properties>
- <activation>
- <activeByDefault>true</activeByDefault> <!--默认启动环境-->
- </activation>
- </profile>
- <profile>
- <id>env_pro</id>
- <properties>
- <profile.active>pro</profile.active>
- </properties>
- </profile>
- </profiles>
- ```
-
- **SpringBoot中读取maven设置值**
-
- ```yaml
- spring:
- profiles:
- active: @profile.active@
- ```
注意:如果pom.xml文件当中设置更改了另一个环境为true,但是运行的时候没有更改成功,这个问题是因为idea缓存的原因,你直接再meven当中手动compile一下就可以,所以一般都是在你更新pom文件的时候就compile
- private static final Logger log= LoggerFactory.getLogger(BookController.class);
-
- @GetMapping
- public String toIndex(){
- log.info("info...");
- log.warn("warn...");
- log.error("error...");
- return "log日志文件";
- }
-
-
-
- - TRACE:运行堆栈信息,使用率低
- - DEBUG:程序员调试代码使用
- - INFO:记录运维过程数据
- - WARN:记录运维过程报警数据
- - ERROR:记录错误堆栈信息
- - FATAL:灾难信息,合并计入ERROR
yml配置文件当中更改日志级别
使用lombok快速创建日志对象
- 、、、添加依赖
- <!--lombok-->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
-
-
- 、、、给类加上@Slf4j注解,就可以直接使用了
- @Slf4j
- @RestController
- @RequestMapping("/books")
- public class BookController {
-
- @GetMapping
- public String toIndex(){
- log.info("info...");
- log.warn("warn...");
- log.error("error...");
- return "log日志文件";
- }
- }
- ```yaml
- logging:
- pattern:
- console: "%d %clr(%p) --- [%16t] %clr(%-40.40c){cyan} : %m %n"
- ```
springboot_09_hot_deploy
1、手动启动热部署
(2)、热部署的范围
- ```yaml
- spring:
- devtools:
- restart:
- # 设置不参与热部署的文件或文件夹
- exclude: static/**,public/**,config/application.yml
- ```
(springboot_10_configuration)
注意::松散绑定就是你在配置文件yml当中,可以使用很多种命名方式,我们最常用的就是烤肉串模式,前面使用@configurationProperties获取数据直接全小写就可以了
- 、、、java
- @Data
- @Component
- @ConfigurationProperties(prefix = "servers")
- public class ServerConfig {
- private Duration serverTime;//这个没有绑定单位,所以我们再yml当中的数据带上单位
- @DataSizeUnit(DataUnit.MEGABYTES)//再这里绑定单位就不用再yml当中带单位了
- private DataSize dataSize;
- }
-
- 、、、yaml
- servers:
- serverTime: 10m
- data-size: 100
时间的话再yml配置文件当中默认是ms,所以不好写,datasize是容量大小,再配置文件当中是单位是by,不方便使用,我们可以再定义pojo类的时候给他加上单位
- <!--1.导入JSR303规范-->
- <dependency>
- <groupId>javax.validation</groupId>
- <artifactId>validation-api</artifactId>
- </dependency>
- <!--使用hibernate框架提供的校验器做实现-->
- <dependency>
- <groupId>org.hibernate.validator</groupId>
- <artifactId>hibernate-validator</artifactId>
- </dependency>
这里不用配置版本的原因是我们的springboot里面有
- @Data//lombokchuachua快速创建pojo类
- @Component//注册bean
- @ConfigurationProperties(prefix = "servers")//这个是yml当中提取数据
- //开启校验功能
- @Validated
- public class ServerConfig {
- private String ip;
- @Max(value = 400,message = "最大值不能超过400")//给我们属性添加范围最大值
- private int port;
- }
总结:开启Bean属性校验功能一共3步:
导入JSR303与Hibernate校验框架坐标、
使用@Validated注解启用校验功能、
使用具体校验规则规范数据校验格式
(springboot_11_text)
- @SpringBootTest(properties = {"test.post=testValue1"})//使用临时参数测试程序
- @SpringBootTest(args = {"--test.post=testValue2"})
- //使用args来,这个的话需要加--,和我们之前运输jar的时候设置临时参数一样
- class Springboot11TextApplicationTests {
-
- @Value("${test.post}")
- private String msg;
-
- @Test
- void contextLoads() {
- System.out.println(msg);
- }
-
- }
- 、、、配置类
- @Configuration
- public class MsgConfig {
-
- @Bean
- public String msg(){
- return "MsgConfig";
- }
- }
-
-
- 、、、测试里面导入并且使用
- @SpringBootTest
- @Import(MsgConfig.class)
- public class MsgConfigTest {
-
- @Autowired
- private String msg;
-
- @Test
- void testConfiguration(){
- System.out.println(msg);
- }
-
- }
- 、、、控制器
- @RestController
- @RequestMapping("/books")
- public class BookController {
-
- @GetMapping
- public String toIndex(){
- return "books";
- }
-
- }
-
- 、、、测试类
- //1.这个就是配置虚拟端口,后面的表明端口是随机的
- @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
- //2.开启虚拟mvc调用
- @AutoConfigureMockMvc
- public class WebTest {
-
- @Test
- //3。注入虚拟mvc调用对象
- void indexTest(@Autowired MockMvc mvc) throws Exception {
- //4.创建虚拟请求,当前访问/books
- MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
- //5.执行请求
- ResultActions actions = mvc.perform(builder);
- }
- //这个就是配置虚拟端口,后面的表明端口是随机的
- @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
- //开启虚拟mvc调用
- @AutoConfigureMockMvc
- public class WebTest {
-
-
- @Test
- void testStatus(@Autowired MockMvc mvc) throws Exception {
- //创建虚拟请求
- MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
- //执行请求
- ResultActions actions = mvc.perform(builder);
- //定义本次调用的预期值
- StatusResultMatchers status = MockMvcResultMatchers.status();
- //预计本次调用时成功的状态200
- ResultMatcher ok = status.isOk();
- //添加预计值到本次调用过程中进行匹配
- actions.andExpect(ok);
- }
-
- }
- - 响应体匹配(非json数据格式)
-
- ```JAVA
- @Test
- void testBody(@Autowired MockMvc mvc) throws Exception {
- MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
- ResultActions action = mvc.perform(builder);
- //设定预期值 与真实值进行比较,成功测试通过,失败测试失败
- //定义本次调用的预期值
- ContentResultMatchers content = MockMvcResultMatchers.content();
- ResultMatcher result = content.string("springboot2");
- //添加预计值到本次调用过程中进行匹配
- action.andExpect(result);
- }
- ```
-
- - 响应体匹配(json数据格式,开发中的主流使用方式)
-
- ```JAVA
- @Test
- void testJson(@Autowired MockMvc mvc) throws Exception {
- MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
- ResultActions action = mvc.perform(builder);
- //设定预期值 与真实值进行比较,成功测试通过,失败测试失败
- //定义本次调用的预期值
- ContentResultMatchers content = MockMvcResultMatchers.content();
- ResultMatcher result = content.json("{\"id\":1,\"name\":\"springboot2\",\"type\":\"springboot\"}");
- //添加预计值到本次调用过程中进行匹配
- action.andExpect(result);
- }
- ```
- - 响应头信息匹配
-
- ```JAVA
- @Test
- void testContentType(@Autowired MockMvc mvc) throws Exception {
- MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
- ResultActions action = mvc.perform(builder);
- //设定预期值 与真实值进行比较,成功测试通过,失败测试失败
- //定义本次调用的预期值
- HeaderResultMatchers header = MockMvcResultMatchers.header();
- ResultMatcher contentType = header.string("Content-Type", "application/json");
- //添加预计值到本次调用过程中进行匹配
- action.andExpect(contentType);
- }
- ```
只要注解@Transactional出现的位置存在注解@SpringBootTest,
springboot就会认为这是一个测试程序,无需提交事务,所以也就可以避免事务的提交。
- HikariCP(默认)
- Tomcat提供DataSource
- Commons DBCP
- 、、、使用druid
- ```YAML
- spring:
- datasource:
- druid:
- url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
- driver-class-name: com.mysql.cj.jdbc.Driver
- username: root
- password: root
- ```
-
- 、、、换成是默认的数据源HikariCP后
- 两种方案,第一,直接将druid方法的druid哪一行删除就可以
- 第二:
- spring:
- datasource:
- url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
- hikari:
- driver-class-name: com.mysql.cj.jdbc.Driver
- username: root
- password: root
- maximum-pool-size: 50 //这个配置其他的配置
首先需要导入依赖
- ```xml
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jdbc</artifactId>
- </dependency
- ```
- **步骤④**:使用JdbcTemplate实现查询操作(实体类封装数据的查询操作)
-
- @Test
- void testJdbcTemplate(@Autowired JdbcTemplate jdbcTemplate){
- String sql = "select * from tbl_book";
- //这个是封装数据模型,不封装模型的话,我们使用jdbcTemplate拿到的数据是map数组
- //而封装后我们拿到的就是book类型的数据
- RowMapper<Book> rm = new RowMapper<Book>() {
- @Override
- public Book mapRow(ResultSet rs, int rowNum) throws SQLException {
- Book book = new Book();
- book.setId(rs.getInt("id"));
- book.setName(rs.getString("name"));
- book.setType(rs.getString("type"));
- book.setDescription(rs.getString("description"));
- return book;
- }
- };
- List<Book> list = jdbcTemplate.query(sql, rm);
- System.out.println(list);
- }
如果想对JdbcTemplate对象进行相关配置,可以在yml文件中进行设定,具体如下:
- ```yaml
- spring:
- jdbc:
- template:
- query-timeout: -1 # 查询超时时间
- max-rows: 500 # 最大行数
- fetch-size: -1 # 缓存行数
导入依赖(工程为web工程)
- <dependency>
- <groupId>com.h2database</groupId>
- <artifactId>h2</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- </dependency>
yml当中的配置
spring: h2: console: enabled: true path: /h2 ``` web端访问路径/h2,访问密码123456,如果访问失败,先配置下列数据源, 启动程序运行后再次访问/h2路径就可以正常访问了 ```yaml datasource: url: jdbc:h2:~/test hikari: driver-class-name: org.h2.Driver username: sa password: 123456
注意::其实我们只是换了一个数据库而已,其他的东西都不受影响。一个重要提醒,别忘了,上线时,把内存级数据库关闭,采用M据持久化方ySQL数据库作为数案,关闭方式就是设置enabled属性为false即可。
windows启动redis::redis-server.exe redis.windows.conf
- 、、依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
-
-
-
- 、、、yml配置文件
- spring:
- redis:
- host: localhost
- port: 6379
-
-
这个数据库一般都是数据变化很快,我们一般使用的是robo3T来操作文档库
1.依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-mongodb</artifactId>
- </dependency>
2.使用
- 、、、yml页面当中,url和mysql数据库一样的格式
- spring:
- data:
- mongodb:
- uri: mongodb://localhost/itheima
-
-
- 、、、java
- @SpringBootTest
- class Springboot14MongodbApplicationTests {
-
- @Autowired
- private MongoTemplate mongoTemplate;
-
- @Test
- void testMongo(){
- Book book = new Book();
- book.setId(2);
- book.setName("stringboot");
- book.setType("stringboot");
- book.setDescription("stringboot");
- mongoTemplate.save(book);
- }
-
- @Test
- void testFind(){
- List<Book> books = mongoTemplate.findAll(Book.class);
- System.out.println(books);
- }
-
- }
springboot_15_cache(依赖有lombok,springboot-web,mybatispuls,druid,mysql,test)
- 、、、xml
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-cache</artifactId>
- </dependency>
第二步:再我们的启动程序哪里启动缓存
重点:: 使用缓存技术,一定不能忘记再application哪里添加启用缓存
- @SpringBootApplication
- //启用缓存技术
- @EnableCaching
- public class Springboot15CacheApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(Springboot15CacheApplication.class, args);
- }
-
- }
第四步,再service实现类当中使用缓存、
注意::@Cacheable这个注解存储数据可以拿,可以存,key就是我们设置的key,key对应的值就是我们这个方法的返回值。但是如果你要是那种60秒验证码变更的那种,就需要使用@Cacheput,这个只能往缓存里放数据
- @Override
- @Cacheable(value = "cacheSpring",key = "#id")//这样就对这个方法使用了缓存,
- //value定义的是数据存储的一个大的key,最终的结果存在于key
- public Book selectById(int id) {
- return bookDao.selectById(id);
- }
pojo类
- @Data
- public class SMSCode {
- private String phone;
- private String code;
- }
工具类(获取验证码,和从缓存当中提取验证码)
- @Component
- public class CodeUtils {
- private String[] patch = {"000000","00000","0000","000","00","0",""};
-
- //这个是获取验证码的
- public String generator(String smsPhone){
- //加密获取6位验证码
- int hash = smsPhone.hashCode();
- int encryption = 20011128;
- long result = hash ^ encryption;//第一次加密
- long nowtime = System.currentTimeMillis();
- result = result ^ nowtime;//第二次加密,获取系统时间
- long code = result % 1000000; //获取后六位数字
- code = code < 0 ? -code : code; //取出来的数据可能为负数,所以这里判断一下
- String strCode = code + "";
- int len = strCode.length();
- return patch[len]+strCode; // 因为取出来的数字可能前面为0,而不是六位数,所以需要补零
- }
-
- //这个是从缓存当中拿验证码的,
- //需要注意的是,@Cacheable这个注解的返回值就是我们的value,如果缓存当中有数据,就会返回缓存当中的,没有数据就返回方法的返回值
- @Cacheable(value = "SMSphone",key = "#phone")
- public String get(String phone){
- return null;
- }
- }
service接口和实现类
- 、、、接口
- public interface SMSCodeService {
- public String getCaptcha(String phone);
-
- public boolean ifCaptcha(SMSCode smsCode);
- }
-
-
- 、、、实现类
- @Service
- public class SMSCodeServiceImpl implements SMSCodeService {
-
- @Autowired
- private CodeUtils codeUtils;
-
- //获取验证码
- @Override
- // @Cacheable(value = "SMSphone",key = "#phone")
- @CachePut(value = "SMSphone",key = "#phone")//因为我们只希望向缓存当中存储验证码,不希望第二次请求的时候拿到验证码,所以使用这个注解可以只存不取
- public String getCaptcha(String phone) {
- String smsCode = codeUtils.generator(phone);
- return smsCode;
- }
-
- //判断验证码
- @Override
- public boolean ifCaptcha(SMSCode smsCode) {
- //这个是拿到用户输入的code
- String code = smsCode.getCode();
- //这个是调用工具类当中的方法,拿到缓存当中数据
- String queryCode = codeUtils.get(smsCode.getPhone());
- return code.equals(queryCode);
- }
- }
第一步:再原有的依赖文件上我们的
- <!--ehcache-->
- <dependency>
- <groupId>net.sf.ehcache</groupId>
- <artifactId>ehcache</artifactId>
- </dependency>
第二步:将我们ehcache的配置文件导入进来(ehcache.xml)
- <?xml version="1.0" encoding="UTF-8"?>
- <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
- updateCheck="false">
- <diskStore path="D:\sofo\ehcache" /> //这个是缓存存放的位置
-
- <!--默认缓存策略 -->
- <!-- external:是否永久存在,设置为true则不会被清除,此时与timeout冲突,通常设置为false-->
- <!-- diskPersistent:是否启用磁盘持久化-->
- <!-- maxElementsInMemory:最大缓存数量-->
- <!-- overflowToDisk:超过最大缓存数量是否持久化到磁盘-->
- <!-- timeToIdleSeconds:最大不活动间隔,设置过长缓存容易溢出,设置过短无效果,可用于记录时效性数据,例如验证码-->
- <!-- timeToLiveSeconds:最大存活时间-->
- <!-- memoryStoreEvictionPolicy:缓存清除策略-->
- <defaultCache
- eternal="false"
- diskPersistent="false"
- maxElementsInMemory="1000"
- overflowToDisk="false"
- timeToIdleSeconds="60"
- timeToLiveSeconds="60"
- memoryStoreEvictionPolicy="LRU" />
-
- <!--这里面的name就是我们使用缓存设置的那个value,大的环境的名字,这个可以给它进行配置-->
- <cache
- name="SMSphone"
- eternal="false"
- diskPersistent="false"
- maxElementsInMemory="1000"
- overflowToDisk="false"
- timeToIdleSeconds="10"
- timeToLiveSeconds="10"
- memoryStoreEvictionPolicy="LRU" />
- </ehcache>
第三步:再环境当中将默认的cache该化成ehcache(yml文件当中)
- spring:
- cache:
- type: ehcache
- ehcache:
- config: classpath:ehcache.xml //记住这里,直接导入文件位置找不到的话,就要使用classpath导入
再就可以直接使用了,springboot好的点在于,之前使用的默认的cache,再将ehcache技术导入进来后,我们可以直接使用
- **步骤①**:导入redis的坐标
-
- ```xml
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
- ```
-
- 如果需要对redis作为缓存进行配置,注意不是对原始的redis进行配置,而是配置redis作为缓存使用相关的配置,隶属于spring.cache.redis节点下,注意不要写错位置了。
-
- ```yaml
- spring:
- redis:
- host: localhost
- port: 6379
- cache:
- type: redis
- redis:
- use-key-prefix: false 是否使用前缀名字
- key-prefix: sms_ 我们自己给它加前缀名字
- cache-null-values: false 是否应许存储空值
- time-to-live: 10s 缓存时间
- ```
使用这个技术需要注意的是和redis一样,需要将程序启动,而且暂时springboot内部还没有memcached,所以需要我们导入版本号
导入依赖
- <!--memcached-->
- <dependency>
- <groupId>com.googlecode.xmemcached</groupId>
- <artifactId>xmemcached</artifactId>
- <version>2.4.7</version>
- </dependency>
将memcached纳入ioc管理,配置Bean
- @Configuration
- public class XMemcachedConfig {//这个是我们的memcached缓存技术的配置文件
-
- @Bean
- public MemcachedClient getMemcachedClient() throws IOException {
- //因为MemcachedClient需要通过MemcachedClientBuilder的builder方法获取
- MemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder("localhost:11211");
- MemcachedClient memcachedClient = memcachedClientBuilder.build();
- return memcachedClient;
- }
-
- }
使用方法
- @Service
- public class SMSCodeServiceImpl implements SMSCodeService {
-
- @Autowired
- private CodeUtils codeUtils; (这个是工具类,用来获取我们的6位数字验证码的)
-
-
- @Autowired
- private MemcachedClient memcachedClient;
-
- @Override
- public String getCaptcha(String phone) {
- String generator = codeUtils.generator(phone);
- try {
- //这三个参数,一个是我们的key,一个是效应时间,一个是value
- memcachedClient.set(phone,10,generator);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return generator;
- }
-
- @Override
- public boolean ifCaptcha(SMSCode smsCode) {
- String code = null;
- try {
- code = memcachedClient.get(smsCode.getPhone()).toString();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return smsCode.getCode().equals(code);
- }
-
-
- }
我们可以创建一个pojo类,来存放我们需要配置的属性
然后直接在我们给memcached配置文件里面引用就可以了
目前jetcache支持的缓存方案本地缓存支持两种,远程缓存支持两种,分别如下
- 本地缓存(Local)
- LinkedHashMap
- Caffeine
- 远程缓存(Remote)
- Redis
- Tair
- ///1.添加依赖
- <!--jetcache-->
- <dependency>
- <groupId>com.alicp.jetcache</groupId>
- <artifactId>jetcache-starter-redis</artifactId>
- <version>2.6.2</version>
- </dependency>
-
- 、、、2.yml当中配置
-
- spring:
- main:
- allow-circular-references: true //将循环依赖关闭
-
- jetcache:
- remote:
- default:
- type: redis
- host: localhost
- port: 6379
- poolConfig: //这个必须要配置,不配置的话会报错
- maxTotal: 50
-
-
- 、、、3.使用需要开启jetcache
- @SpringBootApplication
- //jetcache启用缓存的主开关
- @EnableCreateCacheAnnotation
- public class Springboot16JetcacheApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(Springboot16JetcacheApplication.class, args);
- }
-
- }
-
- 、、、4.使用
- @Service
- public class SMSCodeServiceImpl implements SMSCodeService {
-
- @Autowired
- private CodeUtils codeUtils;
-
- @CreateCache(name = "jetcache_",expire = 10,timeUnit = TimeUnit.SECONDS)
- private Cache<String,String> jetcache;
-
- @Override
- public String getCaptcha(String phone) {
- String generator = codeUtils.generator(phone);
- jetcache.put(phone,generator);
- return generator;
- }
-
- @Override
- public boolean ifCaptcha(SMSCode smsCode) {
- String code = jetcache.get(smsCode.getPhone());
- return smsCode.getCode().equals(code);
- }
-
-
- }
注意:: 因为现在的版本使用纯远程有一个依赖循环的bug,所以我们需要在yml配置文件当中将循环依赖关闭
spring:
main:
allow-circular-references: true
- 、、、yml配置
- jetcache:
- local:
- default:
- type: linkedhashmap
- keyConvertor: fastjson
开启jetcache等都和前面一样,值得注意的是,我们在使用的时候可以指定使用哪一种
cacheType = CacheType.LOCAL这个是指定使用本地缓存
- @Service
- public class SMSCodeServiceImpl implements SMSCodeService {
- @CreateCache(name="jetCache_",expire = 1000,timeUnit = TimeUnit.SECONDS,cacheType = CacheType.LOCAL)
- private Cache<String ,String> jetCache;
-
- public String sendCodeToSMS(String tele) {
- String code = codeUtils.generator(tele);
- jetCache.put(tele,code);
- return code;
- }
-
- public boolean checkCode(SMSCode smsCode) {
- String code = jetCache.get(smsCode.getTele());
- return smsCode.getCode().equals(code);
- }
- }
导入依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-quartz</artifactId>
- </dependency>
创建我们需要定时发送的工作,记住,需要让它继承QuartzJobBean
- public class MYQuartz extends QuartzJobBean {
- @Override
- protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
- System.out.println("你好");
- }
- }
配置文件类
- @Configuration
- public class QuartzConfig {//触发器
- @Bean
- public JobDetail printJobDetail(){ //工作明细
- //绑定具体的工作
- return JobBuilder
- .newJob(MYQuartz.class)
- .storeDurably()
- .build();
- }
-
- @Bean
- public Trigger printJobTrigger(){
- //这个是设置发送时间
- ScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
- //绑定对应的工作明细
- return TriggerBuilder
- .newTrigger()
- .forJob(printJobDetail())
- .withSchedule(schedBuilder)
- .build();
- }
- }
这个是springboot自己推出的,更加简单方便
- ```java
- @SpringBootApplication
- //开启定时任务功能
- @EnableScheduling
- public class Springboot22TaskApplication {
- public static void main(String[] args) {
- SpringApplication.run(Springboot22TaskApplication.class, args);
- }
- }
- ```
-
- **步骤②**:定义Bean,在对应要定时执行的操作上方,
- 使用注解@Scheduled定义执行的时间,执行时间的描述方式还是cron表达式
-
- ```java
- @Component
- public class MyBean {
- @Scheduled(cron = "0/1 * * * * ?")
- public void print(){
- System.out.println(Thread.currentThread().getName()+" :spring task run...");
- }
- }
- 导入springboot整合javamail的starter
-
- ```xml
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-mail</artifactId>
- </dependency>
- ```
第二步,yaml配置邮箱登录信息
我们的密码写的是开启smtp服务时候的给的编号
第三步:编写程序,添加发送邮件需要的信息
- ```java
- @Service
- public class SendMailServiceImpl implements SendMailService {
-
- //发送人
- private String from = "test@qq.com";
- //接收人
- private String to = "test@126.com";
- //标题
- private String subject = "测试邮件";
- //正文
- private String context = "测试邮件正文内容";
-
- @Autowired
- private JavaMailSender javaMailSender;
-
- @Override
- public void sendMail() {
- SimpleMailMessage message = new SimpleMailMessage();
- message.setFrom(from+"(小甜甜)"); //这个后面添加了名称,那么发送邮件显示名称就会是我们添加的名称
- message.setTo(to);
- message.setSubject(subject);
- message.setText(context);
- javaMailSender.send(message);
- }
- }
- ```
-
- 将发送邮件的必要信息(发件人、收件人、标题、正文)封装到SimpleMailMessage对象中
- ,可以根据规则设置发送人昵称等。
第四步,运行这个方法即可;
如果需要发送带有附件的邮件,那我们所创建的对象有所区别,但是我们的步骤相差不大
- ```JAVA
- @Service
- public class SendMailServiceImpl2 implements SendMailService {
- @Autowired
- private JavaMailSender javaMailSender;
-
- //发送人
- private String from = "test@qq.com";
- //接收人
- private String to = "test@126.com";
- //标题
- private String subject = "测试邮件";
- //正文
- private String context = "测试邮件正文";
-
- public void sendMail() {
- try {
- MimeMessage message = javaMailSender.createMimeMessage();
- MimeMessageHelper helper = new MimeMessageHelper(message,true); //此处设置支持附件
- helper.setFrom(to+"(小甜甜)");
- helper.setTo(from);
- helper.setSubject(subject);
- helper.setText(context);
-
- //添加附件
- File f1 = new File("springboot_23_mail-0.0.1-SNAPSHOT.jar");
- File f2 = new File("resources\\logo.png");
-
- helper.addAttachment(f1.getName(),f1);
- helper.addAttachment("最靠谱的培训结构.png",f2);
-
- javaMailSender.send(message);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
1. springboot整合javamail其实就是简化了发送邮件的客户端对象JavaMailSender的初始化过程,
通过配置的形式加载信息简化开发过程
目前企业级开发中广泛使用的消息处理技术共三大类,具体如下:
- JMS
- AMQP
- MQTT
server层接口和实现类
- 、、、、接口
- public interface MessageService {
- void sendMessage(String id);
- String doMessage();
-
- }
-
- public interface OrderService {
- void order(String id);
- }
-
- 、、、实现类
- @Service
- public class MessageServiceImpl implements MessageService {
-
- private ArrayList<String> msgList = new ArrayList<String>();
- @Override
- public void sendMessage(String id) {
- msgList.add(id);
- System.out.println("已经将订单纳入待处理"+id);
- }
-
- @Override
- public String doMessage() {
- String id = msgList.remove(0);
- System.out.println(id+"已经处理完毕");
- return id;
- }
- }
-
- @Service
- public class OrderServiceImpl implements OrderService {
- @Autowired
- private MessageService messageService;
-
- @Override
- public void order(String id) {
- //这里写处理业务的操作
- System.out.println("订单开始处理");
- //短信消息处理
- messageService.sendMessage(id);
- System.out.println("订单处理完毕");
- }
- }
表现层::
- @RequestMapping("/orders")
- @RestController
- public class OrderController {
- @Autowired
- private OrderService orderService;
-
- //发送消息
- @PostMapping("/{id}")
- public void order(@PathVariable("id")String id){
- orderService.order(id);
- }
-
- }
- ------------------------
- @RequestMapping("/mes")
- @RestController
- public class MessageController {
-
- @Autowired
- private MessageService messageService;
-
- //接受消息
- @GetMapping
- public String message(){
- String id = messageService.doMessage();
- return id;
- }
- }
-
-
yaml
导入依赖坐标
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-activemq</artifactId>
- </dependency>
yml当中的配置
- server:
- port: 80
-
- spring:
- activemq:
- broker-url: tcp://localhost:61616
- jms:
- template:
- default-destination: xsh 这个是如果后面没有设置消息的存储位置,就用这个
业务层
这里我们在message当中设置的消息的发送和接受,order当中负责消息的发送,调用message当中的消息发送方法
-
- public interface OrderService {
- void order(String id);
- }
-
- @Service
- public class OrderServiceActivemqImpl implements OrderService {
- @Autowired
- private MessageService messageServiceActivemq;
- @Override
- public void order(String id) {
- //这里写处理业务的操作
- System.out.println("订单开始处理");
- //短信消息处理
- messageServiceActivemq.sendMessage(id);
- System.out.println("订单处理完毕");
- }
- }
-
-
- public interface MessageService {
- void sendMessage(String id);
- String doMessage();
-
- }
- @Service
- public class MessageServiceActivemqImpl implements MessageService {
- @Autowired
- private JmsMessagingTemplate jmsMessagingTemplate;
- @Override
- public void sendMessage(String id) {
- System.out.println("待发送短信的订单已纳入处理队列,id:"+id);
- jmsMessagingTemplate.convertAndSend("order.queue.id",id);
- //order.queue.id这个是指定它存放的位置
- }
-
- @Override
- public String doMessage() {
- String id =jmsMessagingTemplate.receiveAndConvert("order.queue.id",String.class);
- //因为前面存储指定了位置,所以这里需要加入取数据的地址
- System.out.println("已完成短信发送业务,id:"+id);
- return id;
- }
- }
-
-
-
表现层:
- @RequestMapping("/orders")
- @RestController
- public class OrderController {
- @Autowired
- private OrderService orderService;
-
- //发送消息
- @PostMapping("/{id}")
- public void order(@PathVariable("id")String id){
- orderService.order(id);
- }
-
- }
-
-
- ----------
- @RequestMapping("/mes")
- @RestController
- public class MessageController {
-
- @Autowired
- private MessageService messageService;
-
- //接受消息
- @GetMapping
- public String message(){
- String id = messageService.doMessage();
- return id;
- }
- }
**步骤④**:使用消息监听器在服务器启动后,监听指定位置,当消息出现后,立即消费消息
- @Component
- public class MessageListener {
- @JmsListener(destination = "order.queue.id")//当这个里面有消息,就会立即执行下面的代码
- @SendTo("order.other.queue.id") //这个会将返回值作为消息发送到括号里面的位置保存起来
- public String receive(String id){
- System.out.println("已完成短信发送业务,id:"+id);
- return "new:"+id;
- }
- }
步骤5:切换消息模型由点对点模型到发布订阅模型,修改jms配置即可
- ```yaml
- spring:
- activemq:
- broker-url: tcp://localhost:61616
- jms:
- pub-sub-domain: true
**总结**
1. springboot整合ActiveMQ提供了JmsMessagingTemplate对象作为客户端操作消息队列
2. 操作ActiveMQ需要配置ActiveMQ服务器地址,默认端口61616
3. 企业开发时通常使用监听器来处理消息队列中的消息,设置监听器使用注解@JmsListener
4. 配置jms的pub-sub-domain属性可以在点对点模型和发布订阅模型间切换消息模型
我们先启动命名服务器,后期的broker
第一步:导入依赖坐标
- <!--rocketmq-->
- <dependency>
- <groupId>org.apache.rocketmq</groupId>
- <artifactId>rocketmq-spring-boot-starter</artifactId>
- <version>2.2.1</version>
- </dependency>
第二步:yml当中的配置
#配置RocketMQ的服务器地址
rocketmq:
name-server: localhost:9876
producer:
group: group_rocketmq #给一个组名
第三步:消息的发送
里面存储消息第一个填写的就是我们写的消息存储的位置
- @Service
- public class MessageServiceRocketmqImpl implements MessageService {
-
- @Autowired
- private RocketMQTemplate rocketMQTemplate;
-
- @Override
- public void sendMessage(String id) {
- System.out.println("已经纳入待处理订单 id:"+id);
- //这个是同步消息
- // rocketMQTemplate.convertAndSend("order_rocketmq_id",id);
- //这个是异步消息
- SendCallback callback = new SendCallback() {
- @Override
- public void onSuccess(SendResult sendResult) {
- System.out.println("异步消息发送成功");
- }
-
- @Override
- public void onException(Throwable throwable) {
- System.out.println("异步消息发送失败");
- }
- };
- rocketMQTemplate.asyncSend("order_rocketmq_id",id,callback);
- }
-
- @Override
- public String doMessage() {
- return null;
- }
-
- }
第四步: 设置监听器,当有消息时候,立即消费消息
- @Component
- @RocketMQMessageListener(topic = "order_rocketmq_id",consumerGroup = "group_rocketmq")
- //这里将组名,还有我们的消息存储的位置
- public class MessageListener implements RocketMQListener<String> {//设置有消息自动消费
- @Override
- public void onMessage(String s) {
- System.out.println("已经完成消息的发送:id:"+s);
- }
- }
**总结**
1. springboot整合RocketMQ使用RocketMQTemplate对象作为客户端操作消息队列
2. 操作RocketMQ需要配置RocketMQ服务器地址,默认端口9876
3. 企业开发时通常使用监听器来处理消息队列中的消息,设置监听器使用注解@RocketMQMessageListener
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。