Внутренний интерфейс четырех шагов создания веб-сайта (SpringBoot+ онлайн)

Spring Boot MyBatis
Внутренний интерфейс четырех шагов создания веб-сайта (SpringBoot+ онлайн)
Эта серия разделена на четыре части:

ноль, предисловие

Чтобы обобщить полученные знания, эта серия статей посвящена моему опыту 2018 года.

В этой статье основное внимание уделяется созданию внутренней службы интерфейса URL-адресов и запуску ее на сервере.
Технические моменты, кратко изложенные в этой статье:SpringBoot,mybaits整合,mysql简单操作,ResetFul接口,文件上传,跨域处理


Во-первых, первоначальная конструкция SpringBoot

1. Создайте новый проект SpringBoot в Idea (с субподрядом следующим образом):

Какую кнопку нажать, чтобы создать новый проект, здесь нет ерунды, перейдите по ссылке: [SpringBoot-01-Первый опыт](ву ву Краткое описание.com/fear/74 0 из 9573…

)

项目分包.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

Две ямы, на которые наступил этот знак:

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.cn/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}

3. Процесс записи + тест на вставку:

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.cn/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


В-четвертых, реализовать API-интерфейс RESTFUL (простой CRUD)

1.POST добавить данные:http://域名:端口/api/android/note

Интерфейс принимает спокойный стиль равномерно: / 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). NOCEVICE: добавить метод сервисного слоя
@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 на контроллер с сервисом.

//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


3. Оптимизация и унификация формы возврата данных и захват исключений

统一返回.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. Используйте классы перечисления для унификации кодов ошибок и обслуживания информации об ошибках.

Он используется для поддержки некоторых списков ошибок, которые можно настраивать и выдавать при перехвате исключений для управления.

Например, запрос идентификатора, который не существует в базе данных, не будет сообщать об ошибке по умолчанию.В этом случае вы можете настроить исключение неизвестного идентификатора и зафиксировать его на уровне службы.

自定义异常.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. Оберните все возвращенные результаты в контроллере в 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 развертывается на сервере для запуска (с использованием Tencent Cloud).

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. Протестируйте API-интерфейс URL-адреса
1) Добавить: ПОСТ:Woohoo.для использования 1994.com:8089/API/Android…

线上插入成功.png

2) Запрос:Woohoo.для использования 1994.com:8089/API/Android…

查询成功.png

3) Доступ к картинкам

线上访问图片.png

До сих пор была реализована простая работа внутренней базы данных и API-интерфейса RESTFUL, хотя это относительно просто.

Вы можете добавить другие 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 Crawler + подготовка данных (селен)


Постскриптум: чешский стандарт

1. История роста и опечатки этой статьи
Исходный код проекта Дата Примечание
V0.1 2018-12-11 Внутренний интерфейс четырех шагов создания веб-сайта (SpringBoot+ онлайн)
V0.2 2018-12-12 Обработка запроса пейджинга, добавление информационного поля
2. Подробнее обо мне
псевдоним QQ WeChat Хобби
Чжан Фэнцзетли 1981462002 zdl1994328 язык
мой гитхаб моя краткая книга Мои самородки персональный сайт
3. Заявление

1 ----Эта статья была первоначально написана Чжан Фэнцзетли, пожалуйста, укажите при перепечатке

2 ----Приглашаем энтузиастов программирования общаться друг с другом
3 ---- Личные способности ограничены, если что-то не так, вы можете критиковать и свидетельствовать, и вы должны смиренно исправить это.
4 ---- Видя это, я благодарю вас за вашу любовь и поддержку


icon_wx_200.png