手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战 Hello,你好呀,我是灰小猿,一个超会写bug的程序猿! 利用国庆期间做了一个基于springboot+vue的前后端分离

大家好,欢迎来到IT知识分享网。

这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

Hello,你好呀,我是灰小猿,一个超会写bug的程序猿!

利用国庆期间做了一个基于springboot+vue的前后端分离的个人博客网站,今天在这里将开发过程和大家分享一下,手把手教你搭建一个自己专属的个人博客。

完整源码放置在Gitee上了,【源码链接

小伙伴们记得⭐star⭐哟!

小伙伴们一键三连关注!灰小猿带你上高速啦🎉🎉🎉**!**

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]⚡项目目录⚡

一、个人博客网站项目整体思路

二、Java后端接口开发

(1)数据库设计

​(2)整合MybatisPlus

(3)统一结果封装

(4)整合shiro+jwt实现安全验证

(5)全局异常处理

(6)实体校验

(7)跨域问题

(8)登录接口开发

(9)博客接口开发

一、个人博客网站项目整体思路

整个项目的设计是前后端分离的,后端使用的是SpringBoot+MybatisPlus设计,前端使用Vue+ElementUI搭建页面。安全验证等操作由shiro安全框架完成,在进行前后端数据交互的时候采用路由传输,同时在前后端解决了跨域问题。博客实现登录功能,在未登录的情况下只能访问博客主页,在登录的状态下可以实现博客的发布与编辑功能。

整个博客主页的博客采用时间线的方式布局,先发布的文章会在最前面展示;博客编辑功能同时支持Markdown编辑器编辑。具体的功能实现小伙伴们继续往下看!

二、Java后端接口开发

(1)数据库设计

在数据库设计上主要就是两个表,一个用户信息表和一个博客信息表,

博客信息表中的数据ID会和用户ID相对应。详细的表结构如下:

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

(2)整合MybatisPlus

平常我们使用的都是mybatis来做数据库操作,MybatisPlus是在Mybatis的基础上兴起的,我个人的理解是它在Mybatis和逆向工程的结合,可以直接读取我们的数据库,并且自动的生成*Mapper.xml、Dao、Service中的代码,提高我们的开发效率。

整合MybatisPlus的步骤如下:

第一步,导入所需jar包

在这里我们需要导入MybatisPlus所依赖的jar包,同时因为MybatisPlus需要涉及到代码的自动生成,所以还需要引入freemarker的页面模版引擎。

        <!--mp-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!--freemarker模版引擎依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
            <scope>runtime</scope>
        </dependency>
        <!--mp代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.2.0</version>
        </dependency>

IT知识分享网

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

第二步、写入配置文件

因为我们需要连接数据库嘛,所以当然需要用到数据库连接驱动,同时还需要在配置文件中进行配置,指定好我们的数据库驱动、用户名、密码、数据库名称这些。

同时还需要指定好MybatisPlus扫描的xml文件,

IT知识分享网#配置数据库信息
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/vueblog?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: ADMIN

#指定mybatisPlus扫描的xml文件
mybatis-plus:
  mapper-locations: classpath*:/mapper/**Mapper.xml

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

第三步、开启mapper接口扫描,添加分页插件

在这里需要实现一个分页插件PaginationInterceptor,使用该分页插件的目的很简单,就是让我们在每次查询到的结果以分页的形式展示出来。该插件是写在MybatisPlusConfig类下的,

**同时还有一点需要注意的是,**在添加该配置文件的时候我们需要在类上增加@MapperScan(“”)注解,在其中传入我们想要将接口写入到的包名,该接口的目的就是执行想要变成实现类的接口所在的包,如@MapperScan(“com.gyg.mapper”)

/** * mybatisPlus配置 */
@Configuration
@EnableTransactionManagement
@MapperScan("com.gyg.mapper")   //指定变成实现类的接口所在的包
public class MybatisPlusConfig {

    /** * 实现一个分页插件PaginationInterceptor * @return */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }

}

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

第四步、生成相关代码

想要通过mybatisplus生成代码,官方是给了我们一个工具类的,通过该工具类,我们可以写入自己的参数,然后就可以自动的生成相关的代码了。

工具类名叫:CodeGenerator ,使用时我们需要将其和springboot的启动类放置在同级目录下。启动运行之后,输入我们想要生成对应代码的表名即可。

工具类的代码比较长,我放置在了gitee上,【源码链接

运行这个代码生成器我们就可以自动的生成相关数据表的mapper、dao、service等内容了!

现在数据库相关的代码已经是基本完成了,

(3)统一结果封装

由于我们的数据都是需要通过json串的形式返回给我们的前端页面的,所以我们就需要对返回的结果进行一个统一的封装。在这里我们可以自定义一个封装类Result,方便我们将数据以统一的格式返回出去。

该封装类中一般需要返回的信息有三个:

  • 状态码code(如200表示操作正确,400表示异常)
  • 结果消息msg
  • 结果数据data

同时在封装类中定义全局方法,用于在不同的状态下返回不同的数据。封装类的代码如下:

IT知识分享网import lombok.Data;

import java.io.Serializable;

/** * 封装一个返回统一格式数据的结果集 */
@Data
public class Result implements Serializable {

    private int code;   //200正常、非200异常
    private String msg;     //提示信息
    private Object data;    //返回数据

    public static Result success(Object data) {
        return success(200,"操作成功",data);
    }

    /** * 消息返回方法 * * @param code * @param msg * @param data * @return */
    public static Result success(int code, String msg, Object data) {
        Result r = new Result();
        r.setCode(code);
        r.setMsg(msg);
        r.setData(data);
        return r;
    }


    public static Result fail(String msg) {
        return fail(400,msg,null);
    }

    public static Result fail(String msg, Object data) {
        return fail(400,msg,data);
    }

    public static Result fail(int code, String msg, Object data) {
        Result r = new Result();
        r.setCode(code);
        r.setMsg(msg);
        r.setData(data);
        return r;
    }

}

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

(4)整合shiro+jwt实现安全验证

在进行安全验证的时候我采用的是shiro+jwt结合的方式,大概验证思路是这样的:

前端将登陆信息传送过来之后,通过shiro的Realm进行安全验证,如果验证不通过,那么直接将错误信息返回到前端。如果登录信息验证通过,就将用户信息存储到服务器端,然后通过jwtUtils工具类根据用户的ID生成一个token,并且将该token放入返回请求的请求头中,携带给浏览器,浏览器在接收到服务器的返回的请求的时候,就会解析并获取到该token,并将该token存储到本地;

这样在浏览器每次向服务器发送请求的时候都会从本地携带上该token,服务器也会对每次浏览器发送的请求进行验证,验证浏览器返回的token和服务器端保存的token是否相同。如果相同就放行进行处理;如果不相同就将错误信息返回到浏览器。

附上一个请求过程的图示:

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

安全验证所用到的类有:

  1. ShiroConfig:用于配置shiro的验证信息
  2. AccountRealm:用于对浏览器返回的登录信息进行验证
  3. JwtToken:封装和获取token中的数据
  4. AccountProfile:登录之后返回的用户信息的一个载体
  5. JwtFilter:jwt过滤器,用于过滤浏览器的请求

其中的代码比较多,我就放置在的Gitee上,小伙伴们可以在其中获取【源码链接】

(5)全局异常处理

无论我们平常在进行什么样的项目开发,进行全局异常处理都是一个非常好的习惯,进行全局异常处理,它可以将我们的错误信息用最简单的方式表示出来,并不会出现大量的报错信息。方便我们查阅,在这里我声明了几个在项目中经常会遇到的报错信息。

/** * 异常处理工具类 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /** * 运行时异常 * @param e * @return */
    @ResponseStatus(HttpStatus.BAD_REQUEST)     //判断返回消息是否正常
    @ExceptionHandler(value = RuntimeException.class)
    public Result handler(RuntimeException e){
        log.error("运行时异常---------->>>" + e);
        return Result.fail(e.getMessage());
    }

    /** * shiro运行异常 * @param e * @return */
    @ResponseStatus(HttpStatus.UNAUTHORIZED)     //判断返回消息是否正常,没有权限异常
    @ExceptionHandler(value = ShiroException.class)
    public Result handler(ShiroException e){
        log.error("shiro异常---------->>>" + e);
        return Result.fail(401,e.getMessage(),null);
    }

    /** * 实体校验异常 * @param e * @return */
    @ResponseStatus(HttpStatus.BAD_REQUEST)     //判断返回消息是否正常,没有权限异常
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Result handler(MethodArgumentNotValidException e){
        log.error("实体检验异常异常---------->>>" + e);
        BindingResult bindingResult = e.getBindingResult();
        ObjectError objectError = bindingResult.getAllErrors().stream().findFirst().get();
        return Result.fail(objectError.getDefaultMessage());
    }

    /** * 处理断言异常 * @param e * @return */
    @ResponseStatus(HttpStatus.BAD_REQUEST)     //判断返回消息是否正常,没有权限异常
    @ExceptionHandler(value = IllegalArgumentException.class)
    public Result handler(IllegalArgumentException e){
        log.error("断言异常异常---------->>>" + e);
        return Result.fail(e.getMessage());
    }

}

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

(6)实体校验

在表单数据提交的时候,我们通常会对数据进行校验,比如不能为空,或长度不能小于指定值等,在前端我们可以通过js插件来完成,但是如果在后端的话,我们可以通过使用Hibernate validatior的方式来进行校验。

在springboot中已经自动集成了Hibernate validatior的校验,我们只需要在代码中直接使用就可以了。

所以我们只需要在实体的属性上添加相应的校验规则就可以了,比如在user实例类中:

/** * * @author 关注公众号:码猿编程日记 * @since 2021-09-21 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("m_user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @NotBlank(message = "用户名不能为空")
    private String username;

    private String avatar;

    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;


    private String password;

    private Integer status;

    private LocalDateTime created;

    private LocalDateTime lastLogin;


}

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

(7)跨域问题

由于我们做的是前后端分离的项目,所以在请求发送上一定会出现同源策略的相关问题,这就需要我们解决跨域问题了,关于在前后端交互中解决跨域问题,我专门写了一篇博客,小伙伴们可以去看那一篇《SpringBoot与Vue交互解决跨域问题

在springboot的后端解决跨域问题的策略比较简单,只需要添加一个类CorsConfig,并且让它实现WebMvcConfigurer接口, 其中代码如下,一般在开发的时候直接将代码复制过去就可以了。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/** * 解决跨域问题 */
@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("*");

    }
}

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

(8)登录接口开发

登录接口的开发思路很简单,就是接收前端发送过来的登录信息,进行验证是否通过。同时还有一个退出登录的接口,传入用户的信息,确定是在登录状态时可以实现退出登录操作。

代码如下;

@RestController
public class AccountController {

    @Autowired
    UserService userService;

    @Autowired
    JwtUtils jwtUtils;


    @PostMapping("/login")
    public Result login(@Validated @RequestBody LoginDto loginDto, HttpServletResponse response) {

        System.out.println("用户名和密码:" + loginDto.getUsername() + " " + loginDto.getPassword());
// 获取到当前用户
        Subject subject = SecurityUtils.getSubject();
// 封装用户名和密码
        UsernamePasswordToken token = new UsernamePasswordToken(loginDto.getUsername(), loginDto.getPassword());

        System.out.println("封装用户名和密码成功!!!");

        try {
// 使用shiro进行用户验证
            subject.login(token);
// 如果验证通过再根据用户名查找到该用户
            User user = userService.getOne(new QueryWrapper<User>().eq("username", loginDto.getUsername()));
            Assert.notNull(user, "用户不存在!");

            if (!user.getPassword().equals(loginDto.getPassword())) {
                return Result.fail("密码错误!");
            }
// 根据用户id生成一个jwt
            String jwt = jwtUtils.generateToken(user.getId());

// 将jwt写入
            response.setHeader("authorization", jwt);
            response.setHeader("Access-Control-Expose-Headers", "authorization");

            // 如果正确就返回用户信息
            return Result.success(MapUtil.builder()
                    .put("id", user.getId())
                    .put("username", user.getUsername())
                    .put("avatar", user.getAvatar())
                    .put("email", user.getEmail())
                    .map()
            );
        } catch (UnknownAccountException e) {
            return Result.fail("用户不存在2");
        } catch (IncorrectCredentialsException e) {
            return Result.fail("密码不正确2");
        }
    }

    /** * 退出登录 * * @return */
    @RequiresAuthentication
    @GetMapping("/logout")
    public Result logout() {
        Subject subject = SecurityUtils.getSubject();
// AccountProfile profile = (AccountProfile) subject.getPrincipal();
// System.out.println(profile.getId());
// 会请求到logout
        subject.logout();

        return Result.success("退出成功");
    }

    @RequiresAuthentication
    @GetMapping("/testlogin")
    public Result testlogin() {
        User user = userService.getById(1L);
        return Result.success(user);
    }


}

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

(9)博客接口开发

博客接口中主要实现的功能有:返回主页信息,返回指定博客信息,编辑和发布博客、删除博客的功能,其中编辑和删除博客只有在登录状态下才能请求成功,其他两个请求无需进行登录。

代码如下:

/** * @author 关注公众号:码猿编程日记 * @since 2021-09-21 */
@RestController
//@RequestMapping("/blog")
public class BlogController {

    @Autowired
    BlogService blogService;

    /** * 分页博客页 * * @param currentPage * @return */
    @GetMapping("/blogs")
    public Result list(@RequestParam(defaultValue = "1") Integer currentPage) {
        Page page = new Page(currentPage, 5);

        AccountProfile accountProfile =  (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        System.out.println(accountProfile);

        IPage<Blog> pageDate = blogService.page(page, new QueryWrapper<Blog>().orderByDesc("created"));

        return Result.success(pageDate);
    }

    /** * 查找指定的博客 * * @param id * @return */
    @GetMapping("/blog/{id}")
    public Result detail(@PathVariable(name = "id") long id) {

        Blog blog = blogService.getById(id);
// 用断言来来判断文章是否找不到
        Assert.notNull(blog, "该博客已经被删除!");

// 返回该博客数据
        return Result.success(blog);
    }

    /** * @param blog * @return */
// 只有登录之后才能编辑
    @RequiresAuthentication
    @PostMapping("/blog/edit")
    public Result edit(@Validated @RequestBody Blog blog) {

        System.out.println("编辑测试11111111111111111");
        System.out.println(blog.toString());
        System.out.println("当前用户ID:" + ShiroUtil.getProfile().getId());
        System.out.println(blog.toString());
// System.out.println("当前用户id:" + ShiroUtil.getSubjectID());

        Blog temp = null;
        // 如果博客id不为空,就是编辑
        if (blog.getId() != null) {
            temp = blogService.getById(blog.getId());
// 每一个用户只能编辑自己的文章
            Assert.isTrue(temp.getUserId().equals(ShiroUtil.getProfile().getId()), "你没有权限编辑");

        } else {
            // 如果id为空,就是添加
            temp = new Blog();
// 将这篇文章添加给当前用户的id
            temp.setUserId(ShiroUtil.getProfile().getId());
// 博客创建时间
            temp.setCreated(LocalDateTime.now());
            temp.setStatus(0);
        }

        // 将两个对象进行复制,指定那些字段不复制
        //BeanUtil.copyProperties("转换前的类","转换后的类");
        BeanUtil.copyProperties(blog, temp, "id", "userId", "created", "status");

        //保存或者更新这一篇文章
        blogService.saveOrUpdate(temp);

        return Result.success("操作成功");
    }

    /** * 根据博客ID删除博客 * @param id * @return */
    @RequiresAuthentication
    @PostMapping("/blog/delete/{id}")
    public Result deleteBlog(@PathVariable("id") long id){
        System.out.println(id);
        System.out.println("------------");
// int bid = Integer.parseInt(id);
        boolean isRemove = blogService.removeById(id);
        if (!isRemove){
            return Result.fail("删除失败!");
        }
        return Result.success("删除成功!");
    }

}

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

以上就是我们后台接口开发的全部过程,在开发完成之后需要进行相关的接口测试,测试完成无误之后就可以进行前台页面的开发了。

最后

项目源码我放在gitee了,【源码链接】,小伙伴们别忘了star哟!

**一键三连加关注!灰小猿带你上高速啦!**✨✨✨

我是灰小猿,我们下期见!

手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]手把手教你搭建一个前后台分离的个人博客系统—后台实现[亲测有效]

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/9426.html

(0)
上一篇 2023-02-06 18:00
下一篇 2023-02-06 20:00

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信