一 动态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接⼝
*/
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)还有一种方式是前端来进行转换对象
在此,我们的图书管理项目大体是完成了