Spring(Mybatis进阶)

一 动态Sql

    我们通常在注册一个账号时  ,会有必填字段和非必填字段,我们该如何在程序中实现

1.通过if<>标签,实现动态标签,如图所示,我们让性别选填,然后把整个sql放在script标签下面

           

2.<trim>标签

    trim里有几个标签

• prefix:表⽰整个语句块,以prefix的值作为前缀

• suffix:表⽰整个语句块,以suffix的值作为后缀

• prefixOverrides:表⽰整个语句块要去除掉的前缀

• suffixOverrides:表⽰整个语句块要去除掉的后缀

3.<where>标签 

<where> 只会在⼦元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的AND 或者OR

以上标签也可以使⽤ <trim prefix="where" prefixOverrides="and"> 替换,但是此种情况下,当⼦元素都没有内容时,where关键字也会保留

4.<set>标签

  需求:根据传⼊的⽤⼾对象属性来更新⽤⼾数据,可以使⽤标签来指定动态内容.

5.<foreach>标签

对集合进⾏遍历时可以使⽤该标签。标签有如下属性:

• collection:绑定⽅法参数中的集合,如List,Set,Map或数组对象

• item:遍历时的每⼀个对象

• open:语句块开头的字符串

• close:语句块结束的字符串

• separator:每次遍历之间间隔的字符串

需求:根据多个userid,删除⽤⼾数据

 例子如下

  

6.<include>标签

在xml映射⽂件中配置的SQL,有时可能会存在很多重复的⽚段,此时就会存在很多冗余的代码
我们可以对重复的代码⽚段进⾏抽取,将其通过 <sql> 标签封装到⼀个SQL⽚段,然后再通过<include> 标签进⾏引⽤。

• <sql> :定义可重⽤的SQL⽚段

• <include> :通过属性refid,指定包含的SQL⽚段

二 表白墙 ;

  我们之前写过表白墙案例,但是并没有连接到数据库中,这次我们对这个案例进行升级

我们写出数据库相关的代码

  1.创建Mapper接口,里面具体实现怎么调用数据库

   

package com.example.demo.Mapper;

import com.example.demo.model.MessageInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface MessageMapper {

    @Insert("insert into message_info(`from`,`to`,`message`) values (#{from},#{to},#{message})")
    public void InsertMessage(MessageInfo messageInfo ) ;

    @Select("select * from message_info where delete_flag=0")
    List<MessageInfo> selectAll();

}

这里我们定义了两个接口,一个是添加留言,一个是查看所有留言

 2.创建Service类,来调用接口

package com.example.demo.Service;


import com.example.demo.Mapper.MessageMapper;
import com.example.demo.model.MessageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class MessageService {
    @Autowired
    private MessageMapper messageMapper;
    public void addMessage(MessageInfo messageInfo) {
        messageMapper.InsertMessage(messageInfo);
    }

    public List<MessageInfo> getMessageInfo() {
        return messageMapper.selectAll();
    }
}

3.优化messageController类

  把之前写的方法添加进去

package com.example.demo.controller;

import com.example.demo.Service.MessageService;
import com.example.demo.model.MessageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/message")
public class messageController {
    //List<MessageInfo> messageInfos=new ArrayList<>();
    @Autowired
    private MessageService messageService;
    @RequestMapping("/publish")
  public Boolean publishMessage(MessageInfo messageInfo){
        //进行参数的校验
        if(!StringUtils.hasLength(messageInfo.getFrom())
                || !StringUtils.hasLength(messageInfo.getTo())
                ||!StringUtils.hasLength(messageInfo.getMessage())){
            return false;
        }
       messageService.addMessage(messageInfo);
        return true;

  }

  @RequestMapping("/getMessageInfo")
  public List<MessageInfo> getMessageInfo(){
      return messageService.getMessageInfo();


  }
}

三.图书管理系统

我们之前完成了简单的图书管理系统,里面用的都是伪数据,这里学习了mybatis,运用数据库,我们就来真正的图书管理系统

后端返回结果:

1.当前页的内容   2.总条数

我们需要继续完善图书相关的功能,

1.添加图书,

   需要的接口:addBook  参数:BookInfo   返回:告诉前端是否添加成功,成功返回" ",不成功返回添加失败

 1.  写出addBook方法:

           

2.调用bookInfoMapper里的接口

3.使用bookController调用addBook方法,并在里面写出相关逻辑

 先校验参数,再执行addBook方法

2.修改图书

 我们继续完善相关功能,修改图书:我们点击修改图书时,希望把当前图书的信息显示出来,点击确定时 希望把当前修改的结果进行保存

因此,我们需要两个接口:

  1.查询图书信息:根据id

    1.跟拒查询到的id,显示到各个空中去

  a)先在mapper中写出sql语句

    

b)再由bookServie调用mapper

   

c)再在controller类中写出查询的逻辑

   

   最后通过前后端交互在网页上显示出来

   2.修改图书信息:

     a)我们这次使用xml写出sql语句,然后跟mapper中的接口进行绑定

       

      

b)在Servie类中调用mapper中的接口

  

c)在controller中写出更新图书的逻辑

     

3.删除图书

   对于删除这个接口来说,企业很少使用delete语句

  因此,对于删除我们分为两类: 逻辑删除(软删除/通过字段的标识,标识这个数据被删除了)和物理删除(直接把数据删掉,delete)

   通常我们也可以使用物理删除+存档的方式,存档:逻辑删除+存档

  1.定义接口:deleteBook

    参数:bookid,

     ""表示删除成功,不为空表示删除失败

   由于这是物理删除,我们要把它变成逻辑删除,因此接口定义发生变化:

    定义接口:updateBook   参数:bookid= status=0(0状态表示删除)

    返回和updateBook保持一样,只需要编写前端就行

     

4.批量删除

  因为我们采用的逻辑删除,因此批量删除就是批量更新,因此,我们需要批量删除的图书的id的集合

 1.接口定义:batchDelete 

  2.参数:List<Integer> ids ,传递集合需要用到注解@RequestParam或者使用Arrays.asList进行传参

3.返回:如果是"" 批量删除成功,不为空就是删除失败

因此   我们来编写代码:

    1.写出sql语句

        我们依然利用xml来进行编写

         

 2.在Service里调用mapper类

   

3在controller里面调用Service类

    

5.强制登录

  这里就要提到用户状态了,我们现在是用户未登录的情况下也能访问到图书列表,因此,我们需要定义不同的状态码来进行判断,因此前面写的各种接口都显得不是很合理了,我们需要对接口进行封装

我们使用枚举类型来进行封装

但这样的话就会非常麻烦  我们每个接口都需要进行判断和调用,会使代码变得非常的冗杂,因此,

我们接下来需要学习"拦截器"

拦截器是Spring框架提供的核心功能之⼀,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码

也就是说,允许开发人员提前预定义⼀些逻辑,在用户的请求响应前后执行.也可以在用户请求前阻止其执行.

在拦截器当中,开发⼈员可以在应⽤程序中做⼀些通用性的操作,比如通过拦截器来拦截前端发来的请求,判断Session中是否有登录用户的信息.如果有就可以放行,如果没有就进行拦截.

1.拦截器的实现主要分为两步  

     1.定义一个拦截器   2.把拦截器注册到项目中  代码如下

 

这里的意识是执行目标方法之前,执行的逻辑,返回true表示放行,返回false表示拦截

2.拦截器的执行流程

由于这个方法会拦截所有的文件,我们不希望我们的login方法和各种css方法js方法被拦截,所以我们需要添加方法excludePathPatterns,来指定有哪些文件不需要拦截

我们再继续完善拦截器相关的代码,当我们没有进行登录界面存入自己的session时,就会被拦截器拦截

  

我们修改好之后,当我们直接想访问book_list.html时,拦截器就会拦截下来并且返回401状态码

 当我们的后端修改完之后,我们需要修改前端,当前端没有成功拿到相关的数据时,就会报error

    

 

  6 适配器模式

适配器模式,也叫包装器模式.将⼀个类的接口,转换成客⼾期望的另⼀个接口,适配器让原本接口不兼容的类可以合作⽆间.

简单来说就是⽬标类不能直接使⽤,通过⼀个新类进行包装⼀下,适配调用方使用.把两个不兼容的接口通过⼀定的方式使之兼容.

比如下⾯两个接口,本身是不兼容的(参数类型不⼀样,参数个数不⼀样等等)

场景: 前⾯学习的slf4j 就使⽤了适配器模式, slf4j提供了⼀系列打印日志的api, 底层调用的是log4j 或者
logback来打⽇志, 我们作为调用者, 只需要调⽤slf4j的api就行了
**
* slf4j接⼝
*/
 interface Slf4jApi{
 void log(String message);
}
/**
* log4j 接⼝
*/
class Log4j{
 void log4jLog(String message){
 System.out.println("Log4j打印:"+message);
}
}
/**
* slf4j和log4j适配器
*/
    class Slf4jLog4JAdapter implements Slf4jApi{
    private Log4j log4j;
    public Slf4jLog4JAdapter(Log4j log4j) {
    this.log4j = log4j;
}
    @Override
    public void log(String message) {
    log4j.log4jLog(message);
}
}
/**
* 客⼾端调⽤
*/
    public class Slf4jDemo {
    public static void main(String[] args) {
    Slf4jApi slf4jApi = new Slf4jLog4JAdapter(new Log4j());
    slf4jApi.log("使⽤slf4j打印⽇志");
}
}

7.统一管理

强制登录案例中,我们共做了两部分工作

1. 通过Session来判断用户是否登录

2. 对后端返回数据进行封装,告知前端处理的结果

拦截器帮我们实现了第一个功能,接下来看SpringBoot对第二个功能如何支持

我们需要新建一个类,让这个类实现一个接口ResponseBodyAdvice

统⼀的数据返回格式使用 @ControllerAdvice 和 ResponseBodyAdvice 的方式实现 @ControllerAdvice 表示控制器通知类

添加类 ResponseAdvice ,实现 ResponseBodyAdvice 接口,并在类上添加@ControllerAdvice 注解

supports方法:判断是否要执行beforeBodyWrite方法.true为执行,false不执行.通过该方法可以

选择哪些类或哪些方法的response要进行处理,其他的不进行处理

我们去获取响应时,发现String类型时,会发生错误

我们对代码进行修改时,结果正常

原因:SpringMVC默认会注册⼀些自带的 HttpMessageConverter

8.统一异常处理

统⼀异常处理使用的是 @ControllerAdvice +@ExceptionHandler+@ResponseBody

来实现的,

@ControllerAdvice 表示控制器通知类, @ExceptionHandler 是异常处理器,两个结合表

示当出现异常的时候执行某个通知,也就是执行某个方法事件

 我们可以针对很多错误来写统一错误

    1.拦截器 

       作用维度:url

  通过上⾯统⼀功能的添加,我们后端的接口已经发⽣了变化(后端返回的数据格式统⼀变成了Result类型),所以我们需要对前端代码进⾏修改

我们把登录的界面逻辑改成这样

我们重新执行程序,刷新booklist页面,此时我们想让它跳转到登录平台进行强制登录,因此 代码如下

我们进行了统一的管理,因此我们需要对前端的代码进行更改,让前端做出更合理的判断

我们对添加图书的前端进行调整

  a)这里添加图书涉及到了返回结果是string还是json字符串的问题

如果后端返回的结果是string类型,当我们使用统一的结果返回时,返回的是json字符串

content-type是text/html,我们需要把它转换为json

如果是后端进行转换,如图所示

b)还有一种方式是前端来进行转换对象

在此,我们的图书管理项目大体是完成了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值