调查问卷Type Form的集成

这篇具有很好参考价值的文章主要介绍了调查问卷Type Form的集成。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

Typeform是一家制作线上调查问卷的公司。

Muñoz 和 David Okuniev两人于2012年创作出一个更加动态、更具交互性的用户调查工具,每次只提一个问题,并且根据用户的回答为其呈现下一个问题,像和朋友间的对话一样,让用户在不知不觉中就完成了问卷。

Typeform将帮你获得有关产品和经验的反馈,创建和分享反馈、建立联系人表单,进行客户开发调查,结果将以交互式表格的形式快速发送到你的智能手机、平板电脑和台式电脑上。

Type Form 配置

1. 首先注册帐号,然后创建自己的调查问卷模版。 

调查问卷Type Form的集成

 2.配置后端服务的回调地址和验签的密钥。

调查问卷Type Form的集成

3. 根据需要可以配置隐藏的参数,隐藏参数可以通过回调接口传过来。 

调查问卷Type Form的集成

 回调代码

1.开放Type Fome接口无需Token校验。

spring.security 配置不拦截的url.
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    ...

  @Override
  public void configure(WebSecurity web) {
    web.ignoring().antMatchers("/auth/**", "/actuator/health", "/satisfaction/callback");
  }

}

2.拦截Type Fome接口,校验签名。

注册Bean进行全局的url拦截。

  @Bean
  public TypeformFilter typeformContentCacheFilter() {
    return new TypeformFilter();
  }

拦截Type Form的url,然后进行 HmacSha256Signature 签名校验。

注意: filterChain.doFilter(servletRequestWrapper, httpServletResponse),由于HttpServletRequest去读一次后就会释放掉资源,所以需要把请求报文缓存起来。

@Slf4j
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class TypeformFilter extends OncePerRequestFilter {

  public static final String TYPEFORM_SATISFACTION_CALLBACKS = "/satisfaction/callback";

  @Value("${typeform.sha.key}")
  private String key;

  @Override
  public void destroy() {

  }

  @Override
  protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest,
      @NonNull HttpServletResponse httpServletResponse,
      @NonNull FilterChain filterChain) throws ServletException, IOException {
    CachedBodyHttpServletRequest servletRequestWrapper = new CachedBodyHttpServletRequest(
        httpServletRequest);
    String requestUri = servletRequestWrapper.getRequestURI();
    if (requestUri.equals(TYPEFORM_SATISFACTION_CALLBACKS)) {
      String signature = servletRequestWrapper.getHeader("Typeform-Signature");
      String payload = servletRequestWrapper.read();
      if (!validateHmacSha256Signature(signature, payload, key)) {
        httpError(httpServletResponse);
        return;
      }
    }
    filterChain.doFilter(servletRequestWrapper, httpServletResponse);
  }

  private static boolean validateHmacSha256Signature(String signature, String payload, String key) {
    return getHmacSha256(payload, key).equals(signature);
  }

  private static String getHmacSha256(String payload, String key) {
    return "sha256=" + HashUtil.hmacWithAlgorithm("HmacSHA256", payload, key);
  }

  public static void httpError(HttpServletResponse response) throws IOException {
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    PrintWriter out = response.getWriter();
    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");
    out.print("Invalid Request");
    out.flush();
    out.close();
  }

}

hmac算法的工具类,通过算法名称,请求报文,签名密钥获取加密后的报文。 

@Slf4j
public class HashUtil {

  public static String hmacWithAlgorithm(String algorithm, String payload, String key) {
    try {
      SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
      Mac mac = Mac.getInstance(algorithm);
      mac.init(secretKeySpec);
      return Base64.getEncoder().encodeToString((mac.doFinal(payload.getBytes())));
    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
      log.error("hmacWithAlgorithm error", e);
      return null;
    }
  }
}

 CachedBodyHttpServletRequest 缓存了请求报文,以便后续拦截器过滤使用。

缓存代码:this.requestBody = StreamUtils.copyToByteArray(is);

public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {

  private final byte[] requestBody;

  public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
    super(request);
    try (InputStream is = request.getInputStream();) {
      this.requestBody = StreamUtils.copyToByteArray(is);
    }
  }

  @Override
  public ServletInputStream getInputStream() {
    return new ServletInputStreamWrapper(this.requestBody);
  }

  @Override
  public BufferedReader getReader() {
    return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(this.requestBody)));
  }

  public String read() throws IOException {
    BufferedReader reader = this.getReader();
    String line;
    StringBuilder payloadBuilder = new StringBuilder();
    while ((line = reader.readLine()) != null) {
      payloadBuilder.append(line).append(System.lineSeparator());
    }
    return payloadBuilder.toString();
  }

}

@Override
  public ServletInputStream getInputStream() {
    return new ServletInputStreamWrapper(this.requestBody);
  }

因为这里需要返回 ServletInputStream所以还需要包装一个类,因此有了ServletInputStreamWrapper。

 ServletInputStreamWrapper 包装了inputStream类,以便CachedBodyHttpServletRequest进行读取。

package com.veoride.mech.api.component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import lombok.extern.slf4j.Slf4j;

/**
 * @author darmi
 */
@Slf4j
public class ServletInputStreamWrapper extends ServletInputStream {

  public static final int REACH_END = 0;

  private final InputStream inputStream;

  public ServletInputStreamWrapper(byte[] cachedBody) {
    this.inputStream = new ByteArrayInputStream(cachedBody);
  }

  @Override
  public boolean isFinished() {
    try {
      return inputStream.available() == REACH_END;
    } catch (IOException e) {
      log.error("isFinished fail", e);
    }
    return false;
  }

  @Override
  public boolean isReady() {
    return true;
  }

  @Override
  public void setReadListener(ReadListener readListener) {
    throw new UnsupportedOperationException();
  }

  @Override
  public int read() throws IOException {
    return inputStream.read();
  }
}

3.回调业务编写。

根据自己需要完成业务代码编写。文章来源地址https://www.toymoban.com/news/detail-497000.html

@RestController
@RequestMapping
@Slf4j
public class Controller {

  @PostMapping("/satisfaction/callback")
  public void satisfactionCallback(@RequestBody @Valid WebhookDTO webhookDTO) {
    ...
  }

}
package com.veoride.mech.api.dto.typeform;

import com.fasterxml.jackson.annotation.JsonAlias;
import javax.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * @author darmi
 */
@Getter
@Setter
@ToString
public class WebhookDTO {

  @JsonAlias("form_response")
  @NotNull
  private FormResponse formResponse;

  public Long getPhone() {
    return this.formResponse.getHidden().getPhone();
  }

  @Getter
  @Setter
  @ToString
  public static class FormResponse {

    @NotNull
    private Hidden hidden;
  }

  @Getter
  @Setter
  @ToString
  public static class Hidden {

    @NotNull
    private Long phone;
  }


}

总结

  1. 配置Type From的调查问卷信息。
  2. 做好Type From的回调配置,隐藏参数配置以及密钥的配置。
  3. 后端服务完成Type From的请求拦截,以及验证签名和业务处理。注意请求读取后的缓存,以便传递到后续过滤器中。

到了这里,关于调查问卷Type Form的集成的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 仿造问卷星--开发一套调查问卷设计工具(1/3)--完整流程

    一,开发前的准备 第一步,初始化项目 创建package.json 首先,新建一个空文件夹项目,在空文件上按shift键同时鼠标右击,打开命令终端窗口 第二步,安装项目依赖 Parcel 快速部署工具,官网:https://parceljs.org/docs/ Parcel是一款极速零配置WEB应用打包工具,快速、几乎零配置是

    2023年04月08日
    浏览(40)
  • 仿造问卷星--开发一套调查问卷设计工具(3/3)--完整流程

    1,定义一个结果的对象: id,name和questions分别对应问卷id,问卷名称和问卷题目。 2,结果赋值 用户点击生成问卷按钮时, 分别从id和name文本框中获取值 --赋值给resultObj 将上节课拿到的question赋值给刚刚定义的对象: 打印输出结果: json结果: 3,pretty-print-json的使用 引入

    2023年04月11日
    浏览(51)
  • 医院患者满意度调查问卷示例

    以下是一个简单的医院患者满意度调查问卷示例,供参考。请注意,实际的问卷可能需要根据医院的特定需求和目标进行定制。 个人信息(可选): 您的年龄: [填写您的年龄]岁 您的性别: [选择性别] 男性 / 女性 / 其他 1. 您在本次就诊中对医疗护理的满意度: 非常满意

    2024年02月01日
    浏览(52)
  • 求免费好用的问卷调查平台!

    在当今信息时代,了解客户需求和市场趋势对企业的发展至关重要。而问卷调查是一种常见、有效的数据收集方式。本文将介绍一款 专业好用的问卷调查工具 ——Zoho Survey。我们将从功能特点、用户体验、数据分析和安全性四个方面来探讨它为用户带来的价值。 Zoho Survey提供

    2024年02月09日
    浏览(43)
  • 微信小程序开发 案例二 调查问卷

    第一步:主界面代码 **第二步:css样式修改 第三步:安装环境 先安装node.js node.js官网 进入官网安装稳定版本 安装完毕后在同一级创建一个空文件夹 最好都用英文文件夹名 打开新文件夹 打开命令提示符cmd 地址找到新建的文件夹 输入 npm init -y 再输入 npm install express --save 用

    2024年02月09日
    浏览(47)
  • Vue+Element UI完成新建调查问卷

    先看看效果图: 添加填空题:  添加单选题、多选题: 对新增的题目可以上移、下移、编辑、删除操作:  效果大致就是这样,实现代码:    

    2024年02月11日
    浏览(38)
  • 【学习记录】SPSS问卷调查表分析法

    用excel将收集的问卷数据存储,并用SPSS进行数据分析 此例是将收集到的字符型数据转换为易于分析的数值型数据,将列明转换为有代表性的简明的字符数值组合 注:①字符型数据转换为数值型数据:excel中,“查找和选择”-“替换”-“全部替换” ②excel中列数据只保留数值

    2024年02月02日
    浏览(39)
  • 调查问卷平台:企业想做用户调研,怎么施行?

    用户调研是一种获取消费者需求和反馈的重要手段,可以帮助企业更好地了解自己的用户,从而优化产品设计和改善客户服务。那么,如何进行用户调研呢?下面将从几个方面介绍。 首先,需要明确调研目的,以确保调研的有效性。调研目的可以包括: 1、了解目标用户的需

    2024年02月12日
    浏览(38)
  • 泰安柒柒:国外问卷调查都有哪些题?

    提到 问卷调查 我们并不陌生,它经常被用作调查市场 、 商品意见 等多种调查中。 不过,提到国外问卷调查,大家就比较陌生了。简单来说就是 国外的一些企业或机构为了改进自己的商品或服务,会列出一些问题来让大众回答,并用付费或抽奖调查的方式取得大量的用户数

    2024年02月03日
    浏览(43)
  • uniapp + node.js 开发问卷调查小程序

    前后端效果图 后端:nodejs 12.8 ; mongoDB 4.0 前端:uniapp 开发工具:HBuilderX 3.99 前端首页代码 index.vue 后台管理部分页面代码 charts.vue 后端使用 nodejs + mongoDB 搭建服务 程序入口文件 app.js 对原始数据按题目名称进行分组,然后追加需要用到的字段,再把处理好的数据发给前端进行

    2024年01月18日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包