编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

SpringBoot+Vue项目实战之前后端开发实现增删改查

wxchong 2024-08-09 11:36:55 开源技术 12 ℃ 0 评论

场景:公司要开发一个新的项目,但是我们的前端就一个,还要忙着维护处理其他的项目,但是后端人员比较多,所以就要求后台管理系统的页面由后端人员开发,实在不会的找前端协助,这就没办法了,只能自己上了!

前言:登录页面实现好后,这次实现和后端的交互,实现我们经常使用的增删改查,其实就是简单的实现发送请求调用后端编写好的接口,再根据返回的结果动态渲染页面。本次代码有点多,粘贴主要部分,需要的可在文章末尾下载项目

前端项目

先看下这次实现主要用到的页面


接下来就是粘贴主要代码

EditForm.vue

<template>
    <div>
        <i class="el-icon-circle-plus-outline"  @click="dialogFormVisible = true"></i>
        <el-dialog
                title="添加/修改图书"
                :visible.sync="dialogFormVisible"
                @close="clear">
            <el-form v-model="form" style="text-align: left" ref="dataForm">
                <el-form-item label="书名" :label-width="formLabelWidth" prop="title">
                    <el-input v-model="form.title" autocomplete="off" placeholder="不加《》"></el-input>
                </el-form-item>
                <el-form-item label="作者" :label-width="formLabelWidth" prop="author">
                    <el-input v-model="form.author" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="出版日期" :label-width="formLabelWidth" prop="date">
                    <el-input v-model="form.date" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="出版社" :label-width="formLabelWidth" prop="press">
                    <el-input v-model="form.press" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="封面" :label-width="formLabelWidth" prop="cover">
                    <el-input v-model="form.cover" autocomplete="off" placeholder="图片 URL"></el-input>
                    <img-upload @onUpload="uploadImg" ref="imgUpload"></img-upload>
                </el-form-item>
                <el-form-item label="简介" :label-width="formLabelWidth" prop="abs">
                    <el-input type="textarea" v-model="form.abs" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="分类" :label-width="formLabelWidth" prop="cid">
                    <el-select v-model="form.category.id" placeholder="请选择分类">
                        <el-option label="文学" value="1"></el-option>
                        <el-option label="流行" value="2"></el-option>
                        <el-option label="文化" value="3"></el-option>
                        <el-option label="生活" value="4"></el-option>
                        <el-option label="经管" value="5"></el-option>
                        <el-option label="科技" value="6"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item prop="id" style="height: 0">
                    <el-input type="hidden" v-model="form.id" autocomplete="off"></el-input>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="dialogFormVisible = false">取 消</el-button>
                <el-button type="primary" @click="onSubmit">确 定</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script>
    import ImgUpload from '../upload/ImgUpload'
    export default {
        name: 'EditForm',
        components: {ImgUpload},
        data () {
            return {
                dialogFormVisible: false,
                form: {
                    id: '',
                    title: '',
                    author: '',
                    date: '',
                    press: '',
                    cover: '',
                    abs: '',
                    category: {
                        id: '',
                        name: ''
                    }
                },
                formLabelWidth: '120px'
            }
        },
        methods: {
            clear () {
                this.form = {
                    id: '',
                    title: '',
                    author: '',
                    date: '',
                    press: '',
                    cover: '',
                    abs: '',
                    category: ''
                }
            },
            onSubmit () {
                this.$axios
                    .post('/books', {
                        id: this.form.id,
                        cover: this.form.cover,
                        title: this.form.title,
                        author: this.form.author,
                        date: this.form.date,
                        press: this.form.press,
                        abs: this.form.abs,
                        category: this.form.category
                    }).then(resp => {
                    if (resp && resp.status === 200) {
                        this.dialogFormVisible = false
                        this.$emit('onSubmit')
                    }
                })
            },
            uploadImg () {
                this.form.cover = this.$refs.imgUpload.url
            }
        }
    }
</script>

<style scoped>
    .el-icon-circle-plus-outline {
        margin: 50px 0 0 20px;
        font-size: 100px;
        float: left;
        cursor: pointer;
    }
</style>

LibraryIndex.vue

<template>
    <el-container>
        <el-aside style="width: 200px;margin-top: 20px">
            <switch></switch>
            <SideMenu @indexSelect="listByCategory" ref="sideMenu"></SideMenu>
        </el-aside>
        <el-main>
            <books class="books-area" ref="booksArea"></books>
        </el-main>
    </el-container>
</template>

<script>
    import SideMenu from './SideMenu'
    import Books from './Books'
    export default {
        name: "LibraryIndex",
        components: {SideMenu,Books},
        methods: {
            listByCategory () {
                var _this = this
                var cid = this.$refs.sideMenu.cid
                var url = 'categories/' + cid + '/books'
                this.$axios.get(url).then(resp => {
                    if (resp && resp.status === 200) {
                        _this.$refs.booksArea.books = resp.data
                    }
                })
            }
        }
    }
</script>

<style scoped>
    .books-area {
        width: 990px;
        margin-left: auto;
        margin-right: auto;
    }
</style>

后端

LibraryController

package org.jeemp.api.controller;

import org.jeemp.api.pojo.Book;
import org.jeemp.api.service.BookService;
import org.jeemp.api.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * @author JackRen
 * @date 2021-03-07 17:17
 * @description:
 */
@RestController
public class LibraryController {

    @Autowired
    BookService bookService;

    @GetMapping("/api/books")
    public List<Book> list() throws Exception {
        return bookService.list();
    }

    @PostMapping("/api/books")
    public Book addOrUpdate(@RequestBody Book book) throws Exception {
        bookService.addOrUpdate(book);
        return book;
    }

    @PostMapping("/api/delete")
    public void delete(@RequestBody Book book) throws Exception {
        bookService.deleteById(book.getId());
    }

    @GetMapping("/api/categories/{cid}/books")
    public List<Book> listByCategory(@PathVariable("cid") int cid) throws Exception {
        if (0 != cid) {
            return bookService.listByCategory(cid);
        } else {
            return list();
        }
    }

    @GetMapping("/api/search")
    public List<Book> searchResult(@RequestParam("keywords") String keywords) {
        // 关键词为空时查询出所有书籍
        if ("".equals(keywords)) {
            return bookService.list();
        } else {
            return bookService.Search(keywords);
        }
    }


}

FastDfsController

package org.jeemp.api.controller;

import org.apache.commons.io.IOUtils;
import org.jeemp.api.util.FastDfsUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.logging.Logger;

/**
 * @author JackRen
 * @date 2021-02-05 16:26
 * @description:
 */
@RestController
@RequestMapping("/fastDfs")
public class FastDfsController {

    private static Logger logger = Logger.getLogger("FastDfsController");

    @Autowired
    private FastDfsUtil fastDfsUtil;

    @PostMapping("/upload")
    public String uploadFile(MultipartFile file) throws IOException {
        String s = fastDfsUtil.uploadFile(file);
        String resAccessUrl = fastDfsUtil.getResAccessUrl(s);
        System.out.println(resAccessUrl);
        return resAccessUrl;
    }

    @GetMapping("/download")
    public void downloadFile(String filePath, HttpServletResponse response) throws IOException {
        byte[] bytes = fastDfsUtil.downloadFile(filePath);
        String fileName = "哈哈.jpg";
        response.setContentType("application/force-download");// 设置强制下载不打开
        //方式一
        // fileName=new String(fileName.getBytes(), "ISO8859-1")
        //方式二
        fileName = URLEncoder.encode(fileName, "utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        IOUtils.write(bytes, response.getOutputStream());
    }

    /**
     * 流媒体的方式播放视频,只能从头看到尾,不能手动点击重新看已经看过的内容
     * @param filePath
     * @param response
     * @throws IOException
     */
    @GetMapping("/play")
    public void streamMedia(String filePath, HttpServletResponse response) throws IOException {
        byte[] bytes = fastDfsUtil.downloadFile(filePath);
        IOUtils.copy(new ByteArrayInputStream(bytes), response.getOutputStream());
        response.flushBuffer();
    }

    @GetMapping("/delete")
    public void deleteFile(String filePath) {
        Boolean result = fastDfsUtil.deleteFile(filePath);
    }

}

项目启动后会出现跨域请求问题,加上下面的类:

CorsConfig

package org.jeemp.api.config;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author JackRen
 * @date 2021/3/7
 * 解决跨域问题
 **/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsConfig implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        //允许所有的域访问
        response.setHeader("Access-Control-Allow-Origin", "*");
        //允许所有方式的请求
        response.setHeader("Access-Control-Allow-Methods", "*");
        //头信息缓存有效时长(如果不设 Chromium 同时规定了一个默认值 5 秒),没有缓存将已OPTIONS进行预请求
        response.setHeader("Access-Control-Max-Age", "3600");
        //允许的头信息
        response.setHeader("Access-Control-Allow-Headers", "*");

        response.setStatus(HttpServletResponse.SC_OK);

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(request,response);
        }


    }

    @Override
    public void destroy() {

    }
}

测试



项目下载地址

链接:https://pan.baidu.com/s/1YLJnV3Wh1827QnlrX1QKyg 
提取码:trnd 
复制这段内容后打开百度网盘手机App,操作更方便哦

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表