题主是仿照的黑马springboot课程里面的图书管理页面,仿照做出了一个用户信息页面
添加
修改信息
删除提示
第四页
查询
具有基础的增删改,按条件查询,分页功能,然后可以对异常信息进行简单处理
怎么实现的呢?
首先是数据库表,起名为tb_user,然后id自增,name和email字段必填,最后是把name作了唯一约束,防止添加重复数据
接着就是建spring boot环境,创建的话我勾了SpringMvc的和MySQL,以下是我的application.yml配置
server:
port: 8088
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring
username: root
password: root
mybatis-plus:
global-config:
db-config:
table-prefix: tb_
id-type: auto
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
maven坐标配置
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
然后这个是我的目录结构
看着好像很多,但是实际就三个层,数据层,业务层,表现层三层。
接着开始第一步,domain目录下建一个User实体类
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private String email;
private String address;
private String description;
}
接着是数据层,dao目录下建一个UserDao接口,使用的Mybatis-plus,继承了BaseMapper<User>
@Mapper
public interface UserDao extends BaseMapper<User> {
}
之后开始做测试工作
test目录下创建一个dao测试类,增删改查,查单个,查全部,分页功能,以下是一个增方法的测试,依次测试
@SpringBootTest
public class UserDaoTestCase {
@Autowired
private UserDao userDao;
@Test
void testInsert(){
User user=new User();
user.setName("老李");
user.setEmail("212542908@qq.com");
userDao.insert(user);
}
}
然后需要说一下分页功能需要一个拦截器才能实现,config目录下创建
@Configuration
public class MPConfig {
@Bean
public MybatisPlusInterceptor interceptor(){
MybatisPlusInterceptor interceptor=new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
下一步是做业务层了,需要记住业务层和数据层不太一样,它关注的是业务,而不是具体的操作,这个是你对业务的理解,所以可能出现业务层方法和数据层方法名字不一样的情况。
IUserService接口
public interface IUserService extends IService<User> {
//这个方法后面用不到,可以不写
public IPage<User> getPage(int currentPage,int pageSize);
public IPage<User> getPage(int currentPage,int pageSize,User user);
}
实现类,同样是MyBatisPlus
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements IUserService {
@Autowired
private UserDao userDao;
@Override
public IPage<User> getPage(int currentPage, int pageSize, User user) {
LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<>();
lqw.like(Strings.isNotEmpty(user.getName()),User::getName,user.getName());
lqw.like(Strings.isNotEmpty(user.getAddress()),User::getAddress,user.getAddress());
lqw.like(Strings.isNotEmpty(user.getDescription()),User::getDescription,user.getDescription());
IPage page=new Page(currentPage,pageSize);
userDao.selectPage(page,lqw);
return page;
}
}
接着是测试业务层方法了。
同数据层做的一样,不过这次建的是Service的测试用例。
@SpringBootTest
public class UserServiceTestCase {
@Autowired
private IUserService userService;
@Test
void testInsert(){
User user=new User();
user.setName("小丽菊");
user.setEmail("212516523@qq.com");
userService.save(user);
}
}
做完之后就到了表现层的模块了
表现层需要做的方法比较多,因为这次没有MyBatis-plus帮我们了,然后解释下为什么要返回一个Result,这个是为了统一数据格式,统一前端接收到的内容不要一下是A类型,一下是B类型,C类型。这个是叫做前后端数据通信协议来着。
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private IUserService userService;
@PostMapping
public Result save(@RequestBody User user) throws Exception {
if(user.getName().equals("王五")) throw new IOException();
boolean flag = userService.save(user);
return new Result(flag,flag?"添加成功":"添加失败");
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id){
boolean flag = userService.removeById(id);
return new Result(flag,flag?"删除成功":"数据同步失败,自动刷新");
}
@PutMapping
public Result update(@RequestBody User user){
boolean flag = userService.updateById(user);
return new Result(flag,flag?"修改成功":"修改失败");
}
@GetMapping
public Result getAll(){
List<User> data = userService.list();
return new Result(true,data,data==null?"您请求的数据不对噢,请重新尝试":"");
}
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id){
User data = userService.getById(id);
return new Result(true,data,data!=null?"":"数据同步失败,自动刷新");
}
// @GetMapping("/{currentPage}/{pageSize}")
// public Result getPage(@PathVariable Integer currentPage, @PathVariable Integer pageSize){
// IPage<User> data = userService.getPage(currentPage, pageSize);
//
//
// return new Result(true,data,data==null?"您请求的数据不对噢,请重新尝试":"");
// }
@GetMapping("/{currentPage}/{pageSize}")
public Result getPage(@PathVariable Integer currentPage, @PathVariable Integer pageSize,User user){
IPage<User> page = userService.getPage(currentPage, pageSize,user);
if(page.getCurrent()>page.getPages()){
page=userService.getPage((int)page.getPages(),pageSize,user);
}
return new Result(true,page,page==null?"您请求的数据不对噢,请重新尝试":"");
}
}
然后这个是我的Result类,flag是标志成功不成功,data是数据,msg是返回给前端的信息
@Data
public class Result {
private Boolean flag;
private Object data;
private String msg;
public Result(Boolean flag) {
this.flag = flag;
}
public Result(Boolean flag, String msg) {
this.flag = flag;
this.msg = msg;
}
public Result(Boolean flag, Object data) {
this.flag = flag;
this.data = data;
}
public Result(Boolean flag, Object data, String msg) {
this.flag = flag;
this.data = data;
this.msg = msg;
}
}
然后还需要做一下异常处理
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public Result doSqlException(SQLIntegrityConstraintViolationException sql){
sql.printStackTrace();
return new Result(false,null,"不能添加重复数据");
}
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
ex.printStackTrace();
return new Result(false,null,"服务器故障,请联系管理员");
}
}
虽然我写了一个具体的sql异常,但是不知道为什么,等到了后面测试的时候,一直进的是通用的异常,有点迷惑,不过无伤大雅。
到了这里,后端部分的内容就全部完结了。
接下来是前端相关的,vue2+element-ui,题主之前学过vue2,但是基本忘了很多,所以有些地方的具体逻辑没有去写很清楚
添加方法,axios发送请求,通过表单数据formData去发送,如果flag标志为真,那么把弹窗打开,提示成功,否则提示失败,然后不管成不成功都要通过getAll刷新数据
//添加
handleAdd () {
axios.post("/users",this.formData).then((res)=>{
if(res.data.flag){
this.dialogFormVisible=false;
this.$message({
message: res.data.msg,
type: 'success'
});
}else{
this.$message.error(res.data.msg);
}
}).finally(()=>{
this.getAll()
})
},
删除,基本同上
// 删除
handleDelete(row) {
//先提示消息框
this.$confirm("你确定要删除吗?", "提示", {
type: "warning"
})
//点击确定
.then(() => {
axios.delete("/users/" + row.id).then((res) => {
if (res.data.flag) {
this.$message.success(res.data.msg);
} else {
// this.$message.error("删除失败")
this.$message.error(res.data.msg);
}//不管删除成功还是删除失败,都要刷新页面
}).finally(() => {
this.getAll()
})
})
//点击取消
.catch(() => {
this.$message.info("取消操作");
})
},
修改,差不多
//修改
handleEdit() {
axios.put("/users", this.formData).then((res) => {
//判断当前操作是否成功
if (res.data.flag) {
//1:关闭弹层
this.dialogFormVisible4Edit = false;
this.$message({
message: res.data.msg,
type: 'success'
});
} else {
this.$message.error(res.data.msg);
}
}).finally(() => {
//2:重新加载数据
this.getAll()
})
},
查找的话是,分页按条件查找去加载数据,但是说白了其实就是写个带分页和带条件的sql语句,没有什么大不了的东西。
//列表
getAll() {
param="?name="+this.pagination.name;
param+="&address="+this.pagination.address;
param+="&description="+this.pagination.description;
// console.log(param)
axios.get("/users/"+this.pagination.currentPage+"/"+this.pagination.pageSize+param).then((res)=>{
// console.log(res.data)
this.pagination.currentPage=res.data.data.current
this.pagination.pageSize=res.data.data.size
this.pagination.total=res.data.data.total
// console.log(res.data.data)
this.dataList=res.data.data.records
})
},
在这个输入框中没输入的话那就单纯只有按条件,输入的话就是按条件+分页的SQL语句
代码方面重要的基本就这样了。