Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >秒懂HTTPS接口(实现篇)

秒懂HTTPS接口(实现篇)

作者头像
高楼Zee
发布于 2019-07-17 09:56:44
发布于 2019-07-17 09:56:44
2.1K00
代码可运行
举报
文章被收录于专栏:7DGroup7DGroup
运行总次数:0
代码可运行

HTTPS接口实现

下面我们来实践使用Java实现一个简单HTTPS接口示例

项目结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
springbootdemo
├─config 配置信息类
├─controller 控制器类
├─entity 实体类
├─enums 枚举类
├─exception 异常类
├─handler 捕获类
├─repository 数据访问类 
├─util 工具类
├─SpringbootdemoApplication 项目启动类
├──resources 资源文件目录
│  ├─application.yml 全局配置文件
│  ├─banner.txt 项目启动banner
│  ├─tomcat.keystore SSL证书
│  ├─logback.xml 日志配置文件

主要特点:

  • Restful风格
  • 统一异常处理
  • SQL预处理

技术选型:

  • 核心框架:Spring Boot 2.1
  • 持久层框架:JPA 2.0
  • 日志管理:Logback
  • 数据库MySQL 5.7
  • 插件:lombok

开发环境:

  • SUN JDK1.8
  • Maven 3.5.4

新建Spring Boot项目

这里使用的IDEIntelliJIDEA2018

引包,配置pom.xml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <!--引入MySQL驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

编写Entity

编写Person实体bean,用于ORM对象关系映射,映射数据库表结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Person实体类
 */

@Entity
@Data
@Table(name = "person")
public class Person {
    //主键自增长
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Integer age;
}

创建一个接口PersonRepository,后续的控制器直接调用该接口继承自JpaRepository的方法,来实现和数据库交互

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 继承JpaRepository,实现与数据库交互(JPA支持自动生成一些基本CURD SQL语句)
 */
public interface PersonRepository extends JpaRepository<Person,Integer> {

}

统一异常处理

自定义异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 自定义异常类
 */

//RuntimeException继承Exception,spring只对继承RuntimeException的异常进行回滚
public class PersonException extends RuntimeException {
    private Integer code;

    public PersonException(ResultEnum resultEnum) {
        super(resultEnum.getMsg());
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}

捕获异常类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@ControllerAdvice
@Slf4j
public class ExceptionHandle {

    /**
     * 捕获异常类
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result handle(Exception e){
        if (e instanceof PersonException){
            PersonException personException = (PersonException) e;
            return ResultUtil.error(personException.getCode(),personException.getMessage());
        }
        log.error("【系统错误】",e);
        return ResultUtil.error(-1,"未知错误");
    }
}

封装异常消息枚举

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 封装异常消息枚举类
 */

public enum ResultEnum {
    UNKONW_ERROR(-1, "未知错误"),
    SUCCESS(0, "成功");

    private Integer code;
    private String msg;

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

封装异常对象实体

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 封装异常对象(Http请求返回的最外层对象)
 * @param <T>
 */

@Data
public class Result<T> {
    //错误码
    private Integer code;
    //提示信息
    private String msg;
    private T date;
}

异常工具类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 异常工具类
 */
public class ResultUtil {
    public static Result sucess(Object obj) {
        Result result = new Result();
        result.setCode(0);
        result.setMsg("sucess");
        result.setDate(obj);
        return result;
    }

    public static Result sucess() {
        Result result = new Result();
        result.setCode(0);
        result.setMsg("sucess");
        return result;
    }

    public static Result error(Integer code, String message) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(message);
        return result;
    }
}

创建RESTful API

风格设计

请求类型

请求路径

功能

Get

/person

获取人员列表

Post

/person

创建一个人员

创建Controller

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 控制器,处理Http/https请求(RESTful API)
 */

@RestController
public class PersonController {
    @Autowired
    PersonRepository personRepository;

    /**
     * 查询所有人员列表(Get方式)
     * @return
     */

    @GetMapping(value = "/person")
    private List<Person> personlist() {
        return personRepository.findAll();
    }

    /**
     * 添加人员 (Post方式)
     * @param person
     * @return
     */
    @PostMapping(value = "/person")
    public Result personAdd(HttpServletRequest request,@RequestBody Person person) {
        return ResultUtil.sucess(personRepository.save(person));
    }
}

使用SSL-HTTPS

Spring Boot中使用HTTPS步骤:

  1. 要有一个SSL证书,证书怎么获取呢?买(通过证书授权机构购买)或者自己生成(通过keytool生成)
  2. 启用HTTPS
  3. 将HTTP重定向到HTTPS(可选)
获取SSL证书

有两种方式可以获取到SSL证书:

  • 自己通过keytool生成;
  • 通过证书授权机构购买;

这里作为演示,采用keytool生成,实际项目中大部分采用的都是购买的方式。 那么怎么使用keytool生成呢? Keytool是Java提供的证书生成工具,如果配置了JAVA_HOME的,直接就可以在控制台进行生成了,这里演示使用的是Mac的终端窗口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
192:~ apple$ keytool -genkey -alias tomcat -keyalg RSA -keystore tomcat.keystore
输入密钥库口令:  
再次输入新口令: 
您的名字与姓氏是什么?
  [Unknown]:  zuozewei
您的组织单位名称是什么?
  [Unknown]:  7DGroup
您的组织名称是什么?
  [Unknown]:  7D
您所在的城市或区域名称是什么?
  [Unknown]:  Beijing
您所在的省//自治区名称是什么?
  [Unknown]:  Beijing
该单位的双字母国家/地区代码是什么?
  [Unknown]:  CN
CN=zuozewei, OU=7DGroup, O=7D, L=Beijing, ST=Beijing, C=CN是否正确?
  []:  y

输入 <tomcat> 的密钥口令
    (如果和密钥库口令相同, 按回车):  
再次输入新口令:

查看生成的SSL证书信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
apple$ keytool -list -keystore tomcat.keystore 
输入密钥库口令:  
密钥库类型: jks
密钥库提供方: SUN

您的密钥库包含 1 个条目

tomcat, 2018-11-29, PrivateKeyEntry, 
证书指纹 (SHA1): 2B:C5:FB:77:2C:5E:DC:5B:C5:E9:9F:06:27:7F:2E:A4:E4:9E:DF:8C

这里解释下命令的各个参数的含义:

  • genkey :生成key;
  • alias :key的别名;
  • dname:指定证书拥有者信息
  • storetype :密钥库的类型为JCEKS。常用的有JKS(默认),JCEKS(推荐),PKCS12,BKS,UBER。每个密钥库只可以是其中一种类型。
  • keyalg :DSA或RSA算法(当使用-genkeypair参数),DES或DESede或AES算法(当使用-genseckey参数);
  • keysize :密钥的长度为512至1024之间(64的倍数)
  • keystore :证书库的名称
  • validity : 指定创建的证书有效期多少天

dname的值详解:

  • CN(Common Name名字与姓氏)
  • OU(Organization Unit组织单位名称)
  • O(Organization组织名称)
  • L(Locality城市或区域名称)
  • ST(State州或省份名称)
  • C(Country国家名称)

这时候在当前目录下就会看到一个文件 tomcat.keystore,到这里SSL证书就有了。

启用HTTPS

默认情况下Spring Boot内嵌的Tomcat服务器会在8080端口启动HTTP服务,Spring Boot允许在全局配置文件中配置HTTP或HTTPS,但是不可同时配置,如果两个都启动,至少有一个要以编程的方式配置,Spring Boot官方文档建议在application配置文件中配置HTTPS,因为HTTPS比HTTP更复杂一些

application.yml中配置HTTPS,配置信息如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
server:
  port: 443
  servlet:
    context-path: /springboot
  ssl:
    key-store: classpath:tomcat.keystore
    key-store-type: jks
    key-alias: tomcat
    key-store-password: zuozewei
    key-store-provider: SUN
    key-password: zuozewei
    enabled: true

注意:请将在上一步生成的证书放到 src/main/resources目录下。

将HTTP请求重定向到HTTPS

由于不能同时在application.l中同时配置两个connector,所以要以编程的方式配置HTTP Connector,然后重定向到HTTPS Connector

编写TomcatHttp配置类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class TomcatHttpConfig {

    /**
     * 配置内置的Servlet容器工厂为Tomcat
     * @return
     */
    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        //添加配置信息,主要是Http的配置信息
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        return tomcat;
    }

    /**
     * 配置一个Http连接信息
     * @return
     */
    private Connector redirectConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8088);
        connector.setSecure(false);
        connector.setRedirectPort(443);
        return connector;
    }
}

自定义启动标志

只需要在 src/main/resources路径下新建一个banner.txt文件,banner.txt中填写好需要打印的字符串内容即可。 一般情况下,我们会借助第三方工具帮忙转化内容,如:

网站:http://www.network-science.de/ascii/ 将文字转化成字符串,

网站:http://www.degraeve.com/img2txt.php 可以将图片转化成字符串。

配置日志配置文件

只需要在 src/main/resources路径下新建一个 logback.xml配置文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n"/>
    <property name="LOG_PATH" value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}"/>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${LOG_FILE}.%d{yyyy-MM-dd}</fileNamePattern>
        </rollingPolicy>
        <encoder charset="UTF-8">
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <appender name="CRAWLER_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/event.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/event.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>
    <logger name="com.business.intelligence.util.CrawlerLogger" level="INFO" additivity="false">
        <appender-ref ref="CRAWLER_LOG"/>
    </logger>
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

配置数据库配置

手动先创建 db_person数据库

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
spring:
  profiles:
    active: a
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    #手动创建db_person数据库
    url: jdbc:mysql://39.105.21.2:3306/db_person?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: zuozewei
    password: zuozewei
jpa:
  hibernate:
    ddl-auto: update
  show-sql: true

启动并测试

启动项目

通过浏览器输入:http://127.0.0.1:8088/springboot/person

我们可以看到浏览器自动重定向到 https://127.0.0.1/springboot/person

点击浏览器上方的证书,我们可以看到使用的SSL证书信息

完整的项目结构

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 7DGroup 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
揭秘webpack5模块打包
​在上一节中我们初步了解了webpack可以利用内置静态模块类型(asset module type)来处理资源文件,我们所知道的本地服务,资源的压缩,代码分割,在webpack构建的工程中有一个比较显著的特征是,模块化,要么commonjs要么esModule,在开发环境我们都是基于这两种,那么通过webpack打包后,如何让其支持浏览器能正常的加载两种不同的模式呢?
Maic
2022/07/28
9900
揭秘webpack5模块打包
Webpack打包commonjs和esmodule混用模块的产物对比
接 Webpack 打包 commonjs 和 esmodule 模块的产物对比 继续,这篇文章来测试下 commonjs 模块和 esmodule 混用的情况,也就是 import 导入 commonjs 的模块,require 导入 esomodule 的模块,看一下它们在 Webpack 下的产物。
windliang
2022/09/23
1.8K0
Webpack打包commonjs和esmodule混用模块的产物对比
《Webpack实战 入门、进阶与调优(第2版)》- 第一章 webpack简介之打包代码分析
用户6256742
2024/06/22
2380
Webpack 原理系列六: 彻底理解 Webpack 运行时
在上一篇文章 有点难的 webpack 知识点:Chunk 分包规则详解 中,我们详细讲解了 Webpack 默认的分包规则,以及一部分 seal 阶段的执行逻辑,现在我们将按 Webpack 的执行流程,继续往下深度分析实现原理,具体内容包括:
Tecvan
2021/12/09
1.6K0
Webpack 原理系列六: 彻底理解 Webpack 运行时
【模块化】:Webpack 是如何将不同规范(ESM、CJS、UMD、AMD、CMD)的模块化代码打包到一起并协调它们运行的?
在一个项目中同时使用 ES6、CJS、CMD、AMD、UMD 5种不同的模块化规范编写代码,并同时应用静态导入、动态导入(Dynamic Import)方法来引用这些模块。观察 Webpack 是如何将这些不同模块化规范的代码打包到一起和协调它们运行的。
WEBJ2EE
2022/03/30
7.4K2
【模块化】:Webpack 是如何将不同规范(ESM、CJS、UMD、AMD、CMD)的模块化代码打包到一起并协调它们运行的?
Webpack 打包 commonjs 和 esmodule 动态引入模块的产物对比
接 Webpack 打包 commonjs 和 esmodule 模块的产物对比 我们来继续分析。这篇文章主要来看一下动态引入,允许我们引入的模块名包含变量。
windliang
2022/09/23
9870
Webpack 打包 commonjs 和 esmodule 动态引入模块的产物对比
webpack学习笔记
原始开发模式各种js文件引入,顺序不能乱,引入的数据太大,各种js之间有关联,可以考虑所有文件复制到一个js文件里,但又有作用域问题、文件太大、可维护性差
kif
2023/02/27
3020
webpack学习笔记
Webpack 打包 commonjs 和 esmodule 模块的产物对比
这篇文章不涉及 Webpack 的原理,只是观察下 Webpack 对 commonjs 和 esmodule 模块打包后的产物,读完后会对模块系统有个更深的了解。
windliang
2022/09/23
6890
Webpack 打包 commonjs 和 esmodule 模块的产物对比
Webpack 模块化原理和SourceMap
原创不易,未经作者允许禁止转载!! Webpack模块化 Webpack打包的代码,允许我们使用各种各样的模块化,但是最常用的是CommonJS、ES Module。 包括如下原理: CommonJS模块化实现原理; ES Module实现原理; CommonJS加载ES Module的原理; ES Module加载CommonJS的原理; CommonJS: 打包前 const { dateFormat, priceFormat } = require('./js/format'); console.
前端LeBron
2021/12/08
5890
Webpack完整打包流程分析
webpack 在前端工程领域起到了中流砥柱的作用,理解它的内部实现机制会对你的工程建设提供很大的帮助(不论是定制功能还是优化打包)。
gogo2027
2022/10/21
1K0
ESM 是如何被 webpack 打包成 CommonJS 格式的
虽然现代主流浏览器已支持 ESM,但 webpack 仍然会将 ESM 转化为 CommonJS,并注入到运行时代码。
山月
2022/11/02
1.7K0
ESM 是如何被 webpack 打包成 CommonJS 格式的
webpack打包出来的文件都是啥
删除掉没用到的 __webpack_require__.d、__webpack_require__.r、 __webpack_require__.t、__webpack_require__.n 、__webpack_require__.o 、 __webpack_require__.p,剩下的代码如下:
用户1515472
2019/07/24
1.3K0
Webapck5核心打包原理全流程解析
Webpack在前端前端构建工具中可以堪称中流砥柱般的存在,日常业务开发、前端基建工具、高级前端面试...任何场景都会出现它的身影。
19组清风
2021/11/18
5790
Webapck5核心打包原理全流程解析
从微组件到代码共享
随着前端应用越来越复杂,越来越庞大。前有巨石应用像滚雪球一般不断的叠高,后有中后台应用随着历史长河不断地积累负债,或者急需得到改善。微前端的工程方案在前端er心中像一道曙光不断的被提起,被实践,多年至今终于有了比较好的指引。它在解决大型应用之间复杂的依赖关系,或是解决我们技术栈的迁移历史负担,都在一定程度上扮演了极其关键的桥梁。
用户6835371
2021/09/03
1.9K0
从微组件到代码共享
构建打包工具Rollup.js入门指南
最近在看Vue源码的时候发现一个新的打包工具Rollup.js,之前没有听说过这个工具,也不了解Rollup.js相比于常用的打包工具webpack有什么异同和优势,随后查了一下了解到Vue,React,D3,Three.js,Moment源码里都有它的身影,Rollup到底什么?这篇文章带你走进Rollup的世界。
用户1462769
2019/08/12
2.9K0
构建打包工具Rollup.js入门指南
自己实现一个简易的模块打包器(干货)
作者:海因斯坦,原文链接:https://juejin.im/post/6893809205183479822
coder_koala
2020/12/17
6430
自己实现一个简易的模块打包器(干货)
webpack打包原理分析和实现(一)
首先,新建一个空文件夹,编辑器(webstrom)打开文件夹,执行npm init -y,生成package.json,在根目录新建webpack.config.js,加入如下代码(webpack 4.0的基础配置)
kiki.
2022/09/29
4110
多图详解,一次性搞懂Webpack Loader
Webpack 是一个模块化打包工具,它被广泛地应用在前端领域的大多数项目中。利用 Webpack 我们不仅可以打包 JS 文件,还可以打包图片、CSS、字体等其他类型的资源文件。而支持打包非 JS 文件的特性是基于 Loader 机制来实现的。因此要学好 Webpack,我们就需要掌握 Loader 机制。本文阿宝哥将带大家一起深入学习 Webpack 的 Loader 机制,阅读完本文你将了解以下内容:
童欧巴
2021/08/20
1.1K0
多图详解,一次性搞懂Webpack Loader
有点难的知识点: Webpack Chunk 分包规则详解
在前面系列文章提到,webpack 实现中,原始的资源模块以 Module 对象形式存在、流转、解析处理。
山月
2021/06/16
1.6K0
有点难的知识点: Webpack Chunk 分包规则详解
关于Rollup那些事
下一代打包工具,这是rollup对自己的定位。如今的前端领域,构建工具并不缺少,每个前端工程师都用过或者听过webpack。可以看到的是像React、Vue等框架的构建工具使用的都是rollup。既然如此,这些框架为什么会选择rollup?它的特性是什么?面对不同场景,我们要怎么选择构建工具?本文将一一为你呈现。
腾讯IVWEB团队
2020/06/24
7350
推荐阅读
相关推荐
揭秘webpack5模块打包
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验