阅读 3010

建站四部曲之后端接口篇(SpringBoot+上线)

本系列分为四篇:

零、前言

本系列为了总结一下手上的知识,致敬我的2018
本篇的重点在于:搭建一个后端的url接口服务,并运行到服务器上
本篇总结的技术点:SpringBootmybaits整合mysql简单操作ResetFul接口文件上传跨域处理


一、SpringBoot初始搭建

1、Idea中新建SpringBoot项目(分包如下):

按哪个键新建项目,这里就不废话了,新手请转到:SpringBoot-01-之初体验

项目分包.png


2、pom.xml添加依赖:
<dependencies>
    <!--mysql依赖-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--mybatis依赖-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.2</version>
    </dependency>
    <!--web依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>RELEASE</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
复制代码

3.配置application.properties(或application.yml,我喜欢后者)

注意修改的:数据库名mycode,用户名:username: XXXX,密码:password: XXXX

spring:
    datasource:
      url: jdbc:mysql://localhost:3306/mycode?useSSL=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&URIEncoding="UTF-8"
      username: root
      password: ****
      driver-class-name: com.mysql.jdbc.Driver

#坑点0 配置mybatis的xml位置
mybatis:
  mapper-locations: classpath:mapper/*.xml
复制代码

mark一下踩的两个坑:

1).好像是MySQL时区的问题,导致连接异常:
>配置时数据库连接参数添加:`&serverTimezone=Asia/Shanghai`可解决

2).一开始用get测试是否插入成功,但是报错了,仔细看了看,貌似是从中文的地方:
>配置时数据库连接参数添加:`&URIEncoding="UTF-8"`
复制代码

二、MySQL的简单总结

1、建库建表
1).确定想要的单体
{
    "id":"1"
    "type": "绘图相关",
    "name": "Android关于Canvas你所知道的和不知道的一切",
    "localPath":"I:\Java\Android\Unit\C\app\src\main\java\com\toly1994\c\view\CanvasView.java",
    "jianshuUrl":"https://www.jianshu.com/p/4bc05f646bfe",
    "juejinUrl":"https://juejin.im/post/6844903705930629128",
    "imgUrl":"域名:端口/android/Android关于Canvas你所知道的和不知道的一切.png",
    "createTime":"2018-11-05"
}
复制代码

2).创建数据库mycode和表android
//创建数据库
CREATE DATABASE mycode;
USE mycode;
//创建表
CREATE TABLE android (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
type VARCHAR(8) NOT NULL,
name VARCHAR(32) NOT NULL,
localPath VARCHAR(120) NOT NULL,
jianshuUrl VARCHAR(120) NOT NULL,
juejinUrl VARCHAR(120) NOT NULL,
imgUrl VARCHAR(120) NOT NULL,
createTime DATE NOT NULL
);
复制代码

创建数据库成功.png


3).为了总结一下联合查询,创建表type
CREATE TABLE type(
   id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
   type_idx  VARCHAR(4)   NOT NULL,
   type  VARCHAR(48)  NOT NULL
 );
复制代码
4).插入类型数据:
INSERT INTO type(type_idx, type)
VALUES('ABCS', '四大组件'), ('C', '绘图相关'), ('D', '自定义控件'),
('F', 'Fragment'), ('G', '开源计划'), ('V', '原生View'),
('MD', '材料设计'), ('L', '底层核心'), ('M', '多媒体相关'),
('N', '网络相关'), ('O', '三方框架'), ('P', '手机设备相关'),
('S', '数据存读相关'), ('T', '纷杂小技术');
复制代码

type.png


2.MySQL语句的简单回顾
-->插入数据:
insert into android(type,name,localPath,jianshuUrl,juejinUrl,imgUrl,createTime)
values (XX,XX,XX,XX,XX,XX,XX)

-->更新数据:
UPDATE android
SET type=XX,name=XX,localPath=XX,jianshuUrl=XX,juejinUrl=XX,imgUrl=XX,createTime=XX
WHERE id=XX

-->查询所有+INNER JOIN
<select id="findALL" resultType="toly1994.com.android_project.bean.Note">
   SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,createTime FROM android AS a
   INNER JOIN type AS t ON a.type = t.type_idx;
</select>

-->根据id查询
SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,createTime FROM android AS a
INNER JOIN type AS t ON a.type = t.type_idx
WHERE a.id=XX

-->根据type查询
SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,createTime FROM android AS a
INNER JOIN type AS t ON a.type = t.type_idx
 WHERE a.type=XX;


-->根据name部分字符查询
SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,createTime FROM android AS a
INNER JOIN type AS t ON a.type = t.type_idx
WHERE name like '%XX%';

-->根据id删除数据
DELETE FROM android
WHERE id=#{id}
复制代码

三、书写流程+插入测试:

1.文件简介

初级搭建.png

1.AndroidProjectApplication.java 启动文件,坑点在加扫包范围  
2.application.yml 配置文件
3.Note.xml 通过sql语句操作数据库映射出实体类返给dao
4.NoteDao.java 数据库操作接口
5.NoteService.java 根据业务逻辑对dao返回的数据进行一定加工
6.Note.java 实体类,用于承接数据库中的数据
7.NoteController.java 核心操作层,生成可访问的url接口,向外暴露
复制代码

下面以插入数据来演示一下操作流程


2.创建实体类:toly1994.com.android_project.bean.Note.java
public class Note {
    private int id;//id
    private String type;//类型
    private String name;//名称
    private String localPath;//路径
    private String jianshuUrl;//简书地址
    private String juejinUrl;//掘金地址
    private String imgUrl;//掘金地址
    private String createTime;//创建时间
    //构造方法,get、set、toString略
}
复制代码

3.映射xml:mapper/Note.xml

根据规范,在相应的位置写出sql语句就可以了
其中#{type}代表dao中方法传入的参数

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--坑点2:命名空间指向对应dao类名-->
<mapper namespace="toly1994.com.android_project.dao.NoteDao">
    <!--坑点3:id为dao中相应方法名-->
    <insert id="insert">
      insert into android(type,name,localPath,jianshuUrl,juejinUrl,imgUrl,createTime)
      values (#{type},#{name},#{localPath},#{jianshuUrl},#{juejinUrl},#{imgUrl},#{createTime})
    </insert>
</mapper>

复制代码

4.数据库操作:toly1994.com.android_project.dao.NoteDao
/**
 * 作者:张风捷特烈
 * 时间:2018/11/19 0019:13:27
 * 邮箱:1981462002@qq.com
 * 说明:dao层---数据库操作
 */
public interface NoteDao {
    //坑点1 java没有保存形参的记录,所以多参数用户@Param("name")起名字,不然无法识别
    int insert(@Param("type") String type,
               @Param("name") String name,
               @Param("localPath") String localPath,
               @Param("jianshuUrl") String jianshuUrl,
               @Param("juejinUrl") String juejinUrl,
               @Param("imgUrl") String imgUrl,
               @Param("createTime") String createTime);
}
复制代码

5.业务层:toly1994.com.android_project.service.NoteService
/**
 * 作者:张风捷特烈
 * 时间:2018/11/19 0019:13:48
 * 邮箱:1981462002@qq.com
 * 说明:Service层---操作dao
 */
@Service
public class NoteService {
    @Autowired
    private NoteDao mNoteDao;
    @Transactional
    public String insertNote(Note note) {
        mNoteDao.insert(note.getType(), note.getName(),
                note.getLocalPath(), note.getJianshuUrl(),
                note.getJuejinUrl(), note.getImgUrl(),
                note.getCreateTime());
        return "OK";
    }
}
复制代码

6.控制层:toly1994.com.android_project.controller.NoteController
/**
 * 作者:张风捷特烈
 * 时间:2018/11/19 0019:13:34
 * 邮箱:1981462002@qq.com
 * 说明:控制层---生成url接口
 */
@RestController
public class NoteController {
    @Autowired
    private NoteService mNoteService;
    
    @GetMapping("/test/insert")
    public String insert() {
        Note note = new Note("C", "Android关于Canvas你所知道的和不知道的一切",
                "I:\\Java\\Android\\Unit\\C\\app\\src\\main\\java\\com\\toly1994\\c\\view\\CanvasView.java"
                , "https://www.jianshu.com/p/4bc05f646bfe", "https://juejin.im/post/6844903705930629128",
                "http://localhost:8080/android/Android关于Canvas你所知道的和不知道的一切.png", "null");
        mNoteService.insertNote(note);
        return "ok";
    }
}
复制代码

7.启动类:注意坑点,启动类,加扫包
@SpringBootApplication
//坑点5:将dao添加扫包范围
@MapperScan(basePackages = {"toly1994.com.android_project.dao"})
public class AndroidProjectApplication {
    public static void main(String[] args) {
        SpringApplication.run(AndroidProjectApplication.class, args);
    }
}
复制代码

在浏览器上访问接口便可以将数据插入数据库:(这里用GET先测试一下,后面会做成POST)

插入成功.png


四、实现RESTFUL的api接口(简单的CRUD)

1.POST添加数据:http://域名:端口/api/android/note

接口统一采用RESTFUL风格:/api/android/XXX,关于RESTFUL风格,详见:
修改控制器:NoteController,将插入方法改为POST,并在插入后,向访问者返回插入信息(json格式)

/**
 * 作者:张风捷特烈
 * 时间:2018/11/19 0019:13:34
 * 邮箱:1981462002@qq.com
 * 说明:控制层---生成url接口
 */
@RestController
@RequestMapping(value = "/api/android")

public class NoteController {

    @Autowired
    private NoteService mNoteService;

    @PostMapping(value = "/note")
    public Note addOne(@ModelAttribute Note note) {
        mNoteService.insertNote(note);
        return note;
    }
}
复制代码

使用Postman新建一个测试文件夹进行测试.png

POST插入成功.png


2.PUT修改数据:http://192.168.43.60:8089/api/android/note/[id]
1).mapper/Note.xml:添加SQL语句
<update id="updateById">
    UPDATE android
    SET type=#{type},name=#{name},localPath=#{localPath},jianshuUrl=#{jianshuUrl},juejinUrl=#{juejinUrl},imgUrl=#{imgUrl}
    WHERE id=#{id}
</update>
复制代码
2).NoteDao:添加方法接口
/**
 * 通过id修改一条记录
 *
 * @param id
 * @return
 */
void updateById(@Param("id") int id,
                @Param("type") String type,
                @Param("name") String name,
                @Param("localPath") String localPath,
                @Param("jianshuUrl") String jianshuUrl,
                @Param("juejinUrl") String juejinUrl,
                @Param("imgUrl") String imgUrl,
                @Param("createTime") String createTime);
复制代码
3).NoteService:添加Service层方法
@Transactional
public Note updateNote(int id, Note note) {
    mNoteDao.updateById(id,
            note.getType(),
            note.getName(),
            note.getLocalPath(),
            note.getJianshuUrl(),
            note.getJuejinUrl(),
            note.getImgUrl(),
            note.getCreateTime());
    return note;
}
复制代码
4).NoteController:添加url访问接口
@PutMapping(value = "/note/{id}")
public Note updateById(@PathVariable("id") Integer id, @ModelAttribute Note note) {
    mNoteService.updateNote(id,note);
    return note;
}
复制代码

PUT修改成功.png


3.查询数据:

经过上面几个,应该熟悉写法了:
先在dao添加方法,再写SQL,再将dao用Service过渡一下给Controller

//DAO
/**
 * 查询所有
 * @return
 */
List<Note> findALL();

//SQL语句
<select id="findALL" resultType="toly1994.com.android_project.bean.Note">
    SELECT*FROM android
</select>

//Service
public List<Note> findAll() {
    return mNoteDao.findALL();
}

//Controller
@GetMapping(value = "/note")
public List<Note> findAll() {
    return mNoteService.findAll();
}
复制代码

get请求所有.png


4.查询单个(以id字段为例,其他字段类似)
//DAO
/**
 * 根据id查询
 * @return
 */
Note findById(@Param("id") int id);

//SQL语句
<select id="findById" resultType="toly1994.com.android_project.bean.Note">
    SELECT*FROM android
    WHERE id=#{id}
</select>

//Service
public Note findById(int id){
    return mNoteDao.findById(id);
}

//Controller
@GetMapping(value = "/note/{id}")
public Note findById(@PathVariable("id") Integer id) {
    return mNoteService.findById(id);
}
复制代码

根据id查询.png


5.删除单个数据(以id字段为例,其他字段类似)
//DAO
/**
 * 根据id删除
 * @param id
 */
void deleteById(@Param("id") int id);

//SQL语句
<delete id="deleteById">
    DELETE FROM android
    WHERE id=#{id}
</delete>

//Service
@Transactional
public int deleteById(int id){
    mNoteDao.deleteById(id);
    return id;
}

//Controller
@DeleteMapping(value = "/note/{id}")
public int deleteById(@PathVariable("id") Integer id) {
    return mNoteService.deleteById(id);
}
复制代码

根据id删除.png


三、数据返回形式优化统一与异常捕捉

统一返回.png


1.结果统一返回形式
//成功的json:
{
    "code": 200,
    "msg": "操作成功",
    "data": {
        "id": 2,
        "type": "B",
        "name": "BASE",
        "localPath": "c",
        "jianshuUrl": "http://jianshu",
        "juejinUrl": "http://juejin",
        "imgUrl": "imgUrl",
        "create": null
    }
}

//失败的json:
{
    "code": 500,
    "msg": "/ by zero",
    "data": null
}
复制代码

统一数据返回格式.png


2.统一格式实现:
/**
 * 作者:张风捷特烈
 * 时间:2018/5/25:15:30
 * 邮箱:1981462002@qq.com
 * 说明:格式化请求返回值
 */
public class ResultBean<T> {
    private int code;
    private String msg;
    private T data;

    public ResultBean(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    //get、set、toString省略
}
复制代码
3.使用枚举类统一错误码与错误信息维护

用来维护一些错误枚举,可自定义,在捕获异常时对应抛出,以便管理
如默认情况查询一个数据库没有的id是不会报错的,这时可以自定义一个id未知异常,在Service层捕获一下

自定义异常.png

/**
 * 作者:张风捷特烈
 * 时间:2018/5/25:17:36
 * 邮箱:1981462002@qq.com
 * 说明:使用枚举类统一错误码与错误信息维护
 */
public enum ResultEnum {
    SUCCESS(200, "操作成功"),
    EXCEPTION(500, "起它异常"),
    NOT_FOUND_ID(102, "未知id");
    private int code;
    private String msg;
    ResultEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public int getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
}
复制代码
/**
 * 作者:张风捷特烈
 * 时间:2018/5/25:17:14
 * 邮箱:1981462002@qq.com
 * 说明:id未知异常
 */
public class NotFoundIdException extends RuntimeException {
    private int code;
    private static String msg = ResultEnum.NOT_FOUND_ID.getMsg();
    public NotFoundIdException() {
        super(msg);
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
}

复制代码
//Service中捕获异常
public Note findById(int id) {
    Note byId = mNoteDao.findById(id);
    if (byId == null) {
        throw new NotFoundIdException();
    }
    return byId;
}
复制代码

4.结果处理类

使用该类将所有结果转化为ResultBean对象,实现返回值的统一

/**
 * 作者:张风捷特烈
 * 时间:2018/5/30:18:37
 * 邮箱:1981462002@qq.com
 * 说明:结果处理类
 */
public class ResultHandler {
    /**
     * 成功时将object对象转化为ResultBean对象
     *
     * @param o
     * @return
     */
    public static ResultBean ok(Object o) {
        return new ResultBean(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), o);
    }

    /**
     * 使用枚举列举错误类型
     *
     * @param error
     * @return
     */
    public static ResultBean error(ResultEnum error) {
        return new ResultBean(error.getCode(), error.getMsg(), null);
    }

    public static ResultBean error(String e) {
        return new ResultBean(ResultEnum.EXCEPTION.getCode(), e, null);
    }
}
复制代码

5.异常的捕获:

@ExceptionHandler和@ControllerAdvice会让所有的异常走这里,用ResultHandler统一处理
这里可以为项目自定义一些异常

/**
 * 异常捕获类
 */
@ControllerAdvice
public class ExceptionHandle {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResultBean handle(Exception e) {
        return ResultHandler.error(e.getMessage());
    }
}

复制代码

6.将Controller中的所有返回结果都包裹成ResultBean
@RestController
@RequestMapping(value = "/api/android")

public class NoteController {

    @Autowired
    private NoteService mNoteService;

    @PostMapping(value = "/note")
    public ResultBean addOne(@ModelAttribute Note note) {
        mNoteService.insertNote(note);
        return ResultHandler.ok(note);
    }

    @PutMapping(value = "/note/{id}")
    public ResultBean updateById(@PathVariable("id") Integer id, @ModelAttribute Note note) {
        mNoteService.updateNote(id, note);
        return ResultHandler.ok(note);
    }

    @GetMapping(value = "/note")
    public ResultBean findAll() {
        return ResultHandler.ok(mNoteService.findAll());
    }

    @GetMapping(value = "/note/{id}")
    public ResultBean findById(@PathVariable("id") Integer id) {
        return ResultHandler.ok(mNoteService.findById(id));
    }

    @DeleteMapping(value = "/note/{id}")
    public ResultBean deleteById(@PathVariable("id") Integer id) {
        return ResultHandler.ok(mNoteService.deleteById(id));
    }
}

复制代码

五:优化与补充

1.请求总结

总的来说接口有这些:(域名是http://192.168.43.60,端口是:8089 自行修改)

查询:GET请求
查询所有:http://192.168.43.60:8089/api/android/note
查询id=1: http://192.168.43.60:8089/api/android/note/1
查询type=C: http://192.168.43.60:8089/api/android/note/type/C
查询名字有View的:http://192.168.43.60:8089/api/android/note/name/View

插入:POST请求
插入数据:http://192.168.43.60:8089/api/android/note

修改:PUT请求
修改id=1的数据:http://192.168.43.60:8089/api/android/note/1

删除:DELETE请求
删除id=1的数据:http://192.168.43.60:8089/api/android/note/1
复制代码

2、使用内联查询和模糊查询的SQL映射如下:

dao、Service、Controller操作类似,就不贴了

<select id="findALL" resultType="toly1994.com.android_project.bean.Note">
   SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,createTime FROM android AS a
   INNER JOIN type AS t ON a.type = t.type_idx
</select>

<select id="findByType" resultType="toly1994.com.android_project.bean.Note">
   SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,createTime FROM android AS a
   INNER JOIN type AS t ON a.type = t.type_idx
   WHERE a.type=#{type}
</select>

<select id="findById" resultType="toly1994.com.android_project.bean.Note">
   SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,createTime FROM android AS a
   INNER JOIN type AS t ON a.type = t.type_idx
   WHERE a.id=#{id}
</select>

<select id="findByName" resultType="toly1994.com.android_project.bean.Note">
   SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,createTime FROM android AS a
   INNER JOIN type AS t ON a.type = t.type_idx
   where name LIKE concat(concat('%',#{name}),'%')
</select>
复制代码

查询.png

3.服务器资源的访问
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //在F:/SpringBootFiles/Image/下如果有一张 Excalibar.jpg的图片,那么:
        //【1】访问:http://localhost:8080/imgs/Excalibar.jpg 可以访问到
        //【2】html 中 <img src="imgs/Excalibar.jpg">
        registry.addResourceHandler("/imgs/**").addResourceLocations("file:F:/SpringBootFiles/imgs/");
        registry.addResourceHandler("/mp3/**").addResourceLocations("file:F:/SpringBootFiles/mp3/");
        registry.addResourceHandler("/file/**").addResourceLocations("file:F:/SpringBootFiles/file/");
    }
}
复制代码

访问服务器上的文件.png


4.文件的上传接口: UploadController.java
表单上传:http://192.168.43.60:8089/api/android/upload
写流上传:http://192.168.43.60:8089/api/android/postfile

//注意,SpringBoot中表单上传有限定大小2M,修改方式:
spring:
    servlet:
      multipart:
        max-file-size: 10MB
        max-request-size: 100MB
复制代码

@RestController
@RequestMapping(value = "/api/android")
public class UploadController {
    /**
     * 表单上传:多文件上传(包括一个)
     *
     * @param files 上传的文件
     * @return 上传反馈信息
     */
    @PostMapping(value = "/upload")
    public @ResponseBody
    ResultBean uploadImg(@RequestParam("file") List<MultipartFile> files) {
        StringBuilder result = new StringBuilder();
        for (MultipartFile file : files) {
            if (file.isEmpty()) {
                return ResultHandler.error("Upload Error");
            }
            String fileName = file.getOriginalFilename();//获取名字
            String path = "F:/SpringBootFiles/imgs/";
            File dest = new File(path + "/" + fileName);
            if (!dest.getParentFile().exists()) { //判断文件父目录是否存在
                dest.getParentFile().mkdir();
            }
            try {
                file.transferTo(dest); //保存文件
                result.append(fileName).append("上传成功!\n");
            } catch (IllegalStateException | IOException e) {
                e.printStackTrace();
                result.append(fileName).append("上传失败!\n");
            }
        }
        return ResultHandler.ok(result.toString());
    }
    /**
     * 通过流写入服务器
     * @param name
     * @param request
     * @return
     */
    @PostMapping(value = "/postfile")
    public @ResponseBody
    ResultBean postFile(@RequestParam(value = "name") String name, HttpServletRequest request) {
        String result = "";
        ServletInputStream is = null;
        FileOutputStream fos = null;
        try {
            File file = new File("F:/SpringBootFiles/imgs", name);
            fos = new FileOutputStream(file);
            is = request.getInputStream();
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            result = "SUCCESS";
        } catch (IOException e) {
            e.printStackTrace();
            result = "ERROR";
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ResultHandler.ok(result);
    }
}
复制代码

上传文件.png


4.跨域的处理

跨域问题主要就是请求头的问题,详细分析可见:SpringBoot-12-之Ajax跨域访问全解析

AndroidProjectApplication
@SpringBootApplication
//坑点5:将dao添加扫包范围
@MapperScan(basePackages = {"toly1994.com.android_project.dao"})
public class AndroidProjectApplication {

    public static void main(String[] args) {
        SpringApplication.run(AndroidProjectApplication.class, args);
    }

    @Bean
    public FilterRegistrationBean registerFilter() {
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.addUrlPatterns("/*");//所有请求都经过这个Filter
        bean.setFilter(new CrosFilter());//设置过滤器
        return bean;
    }
}
复制代码
toly1994.com.android_project.config.CrosFilter
/**
 * 作者:张风捷特烈
 * 时间:2018/7/22:21:44
 * 邮箱:1981462002@qq.com
 * 说明:解决跨域问题...加头
 */
public class CrosFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse rep = (HttpServletResponse) servletResponse;

        HttpServletRequest req = (HttpServletRequest) servletRequest;

        String origin = req.getHeader("Origin");
        if (!StringUtils.isEmpty(origin)) {
            rep.addHeader("Access-Control-Allow-Origin", origin);
        }
        //动态添加自定义头
        String headers = req.getHeader("Access-Control-Request-Headers");
        if (!StringUtils.isEmpty(headers)) {
            System.out.println(headers);
            rep.addHeader("Access-Control-Allow-Headers", headers);
        }

        //允许8081访问:
//        rep.addHeader("Access-Control-Allow-Origin", "*");
//        rep.addHeader("Access-Control-Allow-Origin", "http://localhost:8081");
        //允许访问方法GET
        rep.addHeader("Access-Control-Allow-Methods", "GET");
        rep.addHeader("Access-Control-Allow-Methods", "POST");
//        rep.addHeader("Access-Control-Allow-Headers", "Content-Type");
        rep.addHeader("Access-Control-Max-Age", "3600");//一小时内缓存预检请求
        rep.addHeader("Access-Control-Allow-Credentials", "true");//允许cookie

        filterChain.doFilter(servletRequest, rep);
    }

    @Override
    public void destroy() {

    }
}
复制代码

四、本地SpringBoot项目部署到服务器上运行(使用腾讯云)

1.打包:

我将端口改为了8089(因为我的服务器开了8089端口)

mvn -Dmaven.test.skip -U clean install
复制代码

2.数据库的备份与恢复

本地备份,服务端恢复

备份:mysqldump -uroot -p mycode >D:\\backupSql\\android.sql
还原:mysql -u root -p mycode< D:\\backupSql\\android.sql
复制代码

数据库恢复.png

备份数据库.png


3.上线

拷贝.png

运行:

F:\>java -jar F:\android_project-0.0.1-SNAPSHOT.jar
复制代码

4.测试url接口api
1)添加:POST:www.toly1994.com:8089/api/android…

线上插入成功.png

2)查询:www.toly1994.com:8089/api/android…

查询成功.png

3)访问图片

线上访问图片.png

至此后端的数据库简单操作及RESTFUl的api接口就已经实现了,虽然比较简单
后期有需要可以再增加其他的url,访问接口有数据了,后端自此告一段落。


2018-12-12补充:添加分页查询:

偏移0,一页20条数据:http://192.168.43.60:8089/api/android/note/0/20

<select id="findByType" resultType="toly1994.com.android_project.bean.Note">
   SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,info,createTime FROM android AS a
   INNER JOIN type AS t ON a.type = t.type_idx
   WHERE a.type=#{type}
   limit #{offset},#{limit}
</select>
复制代码

分类查询分页:http://192.168.43.60:8089/api/android/note/type/ABCS/0/4

<select id="findByName" resultType="toly1994.com.android_project.bean.Note">
   SELECT a.id,name,t.type,localPath,jianshuUrl,juejinUrl,imgUrl,info,createTime FROM android AS a
   INNER JOIN type AS t ON a.type = t.type_idx
   where name LIKE concat(concat('%',#{name}),'%')
   limit #{offset},#{limit}
</select>
复制代码

下篇:建站四部曲之Python爬虫+数据准备篇(selenium)

后记:捷文规范

1.本文成长记录及勘误表
项目源码日期备注
V0.12018-12-11建站四部曲之后端接口篇(SpringBoot+上线)
V0.22018-12-12分页查询的处理,增加info字段
2.更多关于我
笔名QQ微信爱好
张风捷特烈1981462002zdl1994328语言
我的github我的简书我的掘金个人网站
3.声明

1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持


icon_wx_200.png