Jadual Kandungan
七、测试验证 " >七、测试验证
Rumah Java JavaSoalan temu bual Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?

Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?

Aug 22, 2023 pm 03:57 PM
soalan temuduga java

. Nampak dari nada jawapannya dia sedang menghafal karangan berkaki lapan

.

Jadi, untuk membolehkan semua orang merasai dengan mudah pelaksanaan idempoten antara muka, Saudara Tian menyusun artikel ini hari ini

. Artikel ini mempunyai sembilan kandungan utama:

1. Konsep idempotence

imdempotence, dalam istilah orang awam, adalah antara muka yang memulakan permintaan yang sama beberapa kali . Ia mesti dipastikan bahawa operasi hanya boleh dilaksanakan sekali sahaja, contohnya:

  • Antaramuka pesanan, pesanan tidak boleh dibuat beberapa kali
  • Antara muka pembayaran, pembayaran berulang untuk pesanan yang sama hanya boleh ditolak sekali
  • Antara muka panggil balik Alipay, mungkin terdapat beberapa panggilan balik, panggilan balik berulang
    mesti diproses
  • Antara muka penyerahan borang biasa, disebabkan tamat masa rangkaian dan sebab lain, anda hanya boleh klik hantar beberapa kali, dan anda hanya boleh berjaya sekali dan seterusnya

2. Penyelesaian biasa

  1. Indeks unik--halang data kotor baharu
  2. mekanisme token--untuk mengelakkan penyerahan halaman berulang
  3. kunci pesimis--kunci apabila mendapatkan data (jadual kunci atau baris kunci)
  4. dilaksanakan-kunci-optimis berdasarkan nombor versi, semasa mengemas kini data Sahkan data dalam seketika
  5. Kunci teragih - redis (jedis, redisson) atau pelaksanaan penjaga zoo
keadaan mesin - keadaan perubahan, nilai status semasa mengemas kini data

3. Pelaksanaan artikel ini

Redis + token

🎜Artikel ini menggunakan cara kedua untuk melaksanakannya, iaitu melaksanakan pengesahan mati pucuk antara muka melalui mekanisme 🎜. 🎜

4. Idea pelaksanaan

Buat pengecam unik untuk setiap permintaan yang perlu memastikan hilang upayatoken, 先获取token, 并将此token存入redis, 请求接口时, 将此token放到header或者作为请求参数请求接口, 后端接口判断redis中是否存在此token:

  • Jika wujud, proses logik perniagaan seperti biasa dan padamkannya daripada redistoken, maka, jika ia adalah permintaan berulang, disebabkan oleh token telah dipadamkan, ia tidak boleh lulus pengesahan dan mengembalikan Sila jangan ulangi operasiPrompttoken, 那么, 如果是重复请求, 由于token已被删除, 则不能通过校验, 返回请勿重复操作提示
  • 如果不存在, 说明参数不合法或者是重复请求, 返回提示即可

五、项目简介

  • Spring Boot
  • Redis
  • @ApiIdempotent注解 + 拦截器对请求进行拦截
  • @ControllerAdvice全局异常处理
  • 压测工具: Jmeter
Jika ia tidak wujud, ia bermakna parameter tersebut tidak sah atau ia adalah permintaan berulang, pulangkan sahaja prompt

5. Pengenalan Projek

🎜Spring Boot🎜🎜🎜🎜Redis🎜🎜🎜🎜@ApiIdempotent anotasi + pemintas memintas permintaan🎜🎜🎜🎜@ControllerAdvicePengendalian pengecualian global🎜🎜🎜🎜Alat ujian tekanan: Jmeter🎜🎜🎜🎜Penjelasan:🎜🎜🎜Artikel ini memfokuskan pada pelaksanaan teras mati pucuk, tentang bagaimana Spring Boot Butiran penyepaduan redis, ServerResponse, ResponseCode dan butiran lain berada di luar skop artikel ini.🎜. warna latar belakang: rgba(27, 31, 35, 0.05); keluarga fon: 'Operator Mono', Consolas, Monaco, Menlo, monospace;patah perkataan: break-all;warna: rgb(239, 112, 96) ;">maven依赖
<!-- Redis-Jedis -->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.9.0</version>
</dependency>

<!--lombok 本文用到@Slf4j注解, 也可不引用, 自定义log即可-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.10</version>
</dependency>
Salin selepas log masuk

2、JedisUtil
@Component
@Slf4j
public class JedisUtil {

    @Autowired
    private JedisPool jedisPool;

    private Jedis getJedis() {
        return jedisPool.getResource();
    }

    /**
     * 设值
     *
     * @param key
     * @param value
     * @return
     */
    public String set(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.set(key, value);
        } catch (Exception e) {
            log.error("set key:{} value:{} error", key, value, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 设值
     *
     * @param key
     * @param value
     * @param expireTime 过期时间, 单位: s
     * @return
     */
    public String set(String key, String value, int expireTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.setex(key, expireTime, value);
        } catch (Exception e) {
            log.error("set key:{} value:{} expireTime:{} error", key, value, expireTime, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 取值
     *
     * @param key
     * @return
     */
    public String get(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.get(key);
        } catch (Exception e) {
            log.error("get key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 删除key
     *
     * @param key
     * @return
     */
    public Long del(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.del(key.getBytes());
        } catch (Exception e) {
            log.error("del key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 判断key是否存在
     *
     * @param key
     * @return
     */
    public Boolean exists(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.exists(key.getBytes());
        } catch (Exception e) {
            log.error("exists key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 设值key过期时间
     *
     * @param key
     * @param expireTime 过期时间, 单位: s
     * @return
     */
    public Long expire(String key, int expireTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.expire(key.getBytes(), expireTime);
        } catch (Exception e) {
            log.error("expire key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 获取剩余时间
     *
     * @param key
     * @return
     */
    public Long ttl(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.ttl(key);
        } catch (Exception e) {
            log.error("ttl key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    private void close(Jedis jedis) {
        if (null != jedis) {
            jedis.close();
        }
    }

}
Salin selepas log masuk
3、自定义注解@ApiIdempotent
/**
 * 在需要保证 接口幂等性 的Controller的方法上使用此注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIdempotent {
}
Salin selepas log masuk
4、ApiIdempotentInterceptor  拦截器
/**
 * 接口幂等性拦截器
 */
public class ApiIdempotentInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        ApiIdempotent methodAnnotation = method.getAnnotation(ApiIdempotent.class);
        if (methodAnnotation != null) {
            check(request);// 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示
        }

        return true;
    }

    private void check(HttpServletRequest request) {
        tokenService.checkToken(request);
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}
Salin selepas log masuk
5、TokenServiceImpl< /code></h2><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>@Service public class TokenServiceImpl implements TokenService { private static final String TOKEN_NAME = &quot;token&quot;; @Autowired private JedisUtil jedisUtil; @Override public ServerResponse createToken() { String str = RandomUtil.UUID32(); StrBuilder token = new StrBuilder(); token.append(Constant.Redis.TOKEN_PREFIX).append(str); jedisUtil.set(token.toString(), token.toString(), Constant.Redis.EXPIRE_TIME_MINUTE); return ServerResponse.success(token.toString()); } @Override public void checkToken(HttpServletRequest request) { String token = request.getHeader(TOKEN_NAME); if (StringUtils.isBlank(token)) {// header中不存在token token = request.getParameter(TOKEN_NAME); if (StringUtils.isBlank(token)) {// parameter中也不存在token throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg()); } } if (!jedisUtil.exists(token)) { throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg()); } Long del = jedisUtil.del(token); if (del &lt;= 0) { throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg()); } } }</pre><div class="contentsignin">Salin selepas log masuk</div></div><p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">6、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">TestApplication maven依赖

@SpringBootApplication
@MapperScan("com.wangzaiplus.test.mapper")
public class TestApplication  extends WebMvcConfigurerAdapter {

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

    /**
     * 跨域
     * @return
     */
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 接口幂等性拦截器
        registry.addInterceptor(apiIdempotentInterceptor());
        super.addInterceptors(registry);
    }

    @Bean
    public ApiIdempotentInterceptor apiIdempotentInterceptor() {
        return new ApiIdempotentInterceptor();
    }

}
Salin selepas log masuk

2、JedisUtil

@RestController
@RequestMapping("/token")
public class TokenController {

    @Autowired
    private TokenService tokenService;

    @GetMapping
    public ServerResponse token() {
        return tokenService.createToken();
    }

}
Salin selepas log masuk
Salin selepas log masuk

3、自定义注解@ApiIdempotent

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {

    @Autowired
    private TestService testService;

    @ApiIdempotent
    @PostMapping("testIdempotence")
    public ServerResponse testIdempotence() {
        return testService.testIdempotence();
    }

}
Salin selepas log masuk
Salin selepas log masuk

4、ApiIdempotentInterceptor 拦截器

rrreee

5、TokenServiceImpl

rrreee

6、TestApplication

rrreee

好了,以上便是代码的实现部分,下面我们就来验证一下。

七、测试验证

获取token的控制器TokenControllerrrreee

好了,以上便是代码的实现部分,下面我们就来验证一下。🎜🎜🎜耶和华🎜🎜 🎜🎜🎜获取token的控制器TokenController :🎜
@RestController
@RequestMapping("/token")
public class TokenController {

    @Autowired
    private TokenService tokenService;

    @GetMapping
    public ServerResponse token() {
        return tokenService.createToken();
    }

}
Salin selepas log masuk
Salin selepas log masuk

TestController, 注意@ApiIdempotent注解, 在需要幂等性校验的方法上声明此注解即可, 不需要校验的无影响:

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {

    @Autowired
    private TestService testService;

    @ApiIdempotent
    @PostMapping("testIdempotence")
    public ServerResponse testIdempotence() {
        return testService.testIdempotence();
    }

}
Salin selepas log masuk
Salin selepas log masuk

获取token

Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?

查看Redis

Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?

测试接口安全性: 利用Jmeter测试工具模拟50个并发请求, 将上一步获取到的token作为参数

Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?
Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?

header或参数均不传token, 或者token值为空, 或者token值乱填, 均无法通过校验, 如token值为abcd

Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?

8. Nota (sangat penting)

Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?

Dalam gambar di atas, anda tidak boleh memadamkan token secara terus tanpa mengesahkan sama ada pemadaman akan berjaya atau tidak. kerana, Ada kemungkinan beberapa utas boleh mencapai baris 46 pada masa yang sama Pada masa ini, token belum dipadamkan, jadi pelaksanaan diteruskan Jika hasil pemadaman jedisUtil.del(token) tidak disahkan dan dikeluarkan secara langsung, masalah berulang penyerahan masih akan berlaku, walaupun sebenarnya hanya terdapat operasi pemadaman sebenar, hasilkan semula di bawah. . Isu konkurensi, oleh itu, mesti disahkan

.

Baiklah, saya akan kongsikan di sini hari ini.

Atas ialah kandungan terperinci Penemuduga: Dalam antara muka pembayaran, wang hanya boleh ditolak sekali untuk pembayaran berulang untuk pesanan yang sama. Bagaimana untuk melakukan ini?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Arahan sembang dan cara menggunakannya
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Penemubual: Anotasi biasa Spring Aop dan urutan pelaksanaan Penemubual: Anotasi biasa Spring Aop dan urutan pelaksanaan Aug 15, 2023 pm 04:32 PM

Anda mesti tahu Spring, jadi mari kita bincangkan tentang susunan semua pemberitahuan Aop Bagaimana Spring Boot atau Spring Boot 2 mempengaruhi susunan pelaksanaan aop? Beritahu kami tentang perangkap yang anda hadapi dalam AOP?

Temu bual dengan kumpulan tertentu: Jika anda menemui OOM dalam talian, bagaimanakah anda harus menyelesaikan masalah itu? Bagaimana untuk menyelesaikannya? Apakah pilihan? Temu bual dengan kumpulan tertentu: Jika anda menemui OOM dalam talian, bagaimanakah anda harus menyelesaikan masalah itu? Bagaimana untuk menyelesaikannya? Apakah pilihan? Aug 23, 2023 pm 02:34 PM

OOM bermakna terdapat kelemahan dalam program, yang mungkin disebabkan oleh kod atau konfigurasi parameter JVM. Artikel ini bercakap dengan pembaca tentang cara menyelesaikan masalah selepas proses Java mencetuskan OOM.

Novis juga boleh bersaing dengan penemuduga BAT: CAS Novis juga boleh bersaing dengan penemuduga BAT: CAS Aug 24, 2023 pm 03:09 PM

Bab tambahan bagi siri pengaturcaraan serentak Java, C A S (Banding dan tukar), masih dalam gaya yang mudah difahami dengan gambar dan teks, membolehkan pembaca berbual gila dengan penemuduga.

Minggu lepas, saya ada temu bual dengan XX Insurance dan memang bagus! ! ! Minggu lepas, saya ada temu bual dengan XX Insurance dan memang bagus! ! ! Aug 25, 2023 pm 03:44 PM

Minggu lepas, seorang rakan dalam kumpulan pergi untuk temu bual dengan Ping An Insurance Hasilnya agak kesal, tetapi saya harap anda tidak akan berkecil hati, pada dasarnya semua soalan yang dihadapi temu duga boleh diselesaikan dengan menghafal soalan temuduga Ia telah diselesaikan, jadi sila bekerja keras!

Soalan ujian bertulis Ele.me kelihatan mudah, tetapi ia membingungkan ramai orang Soalan ujian bertulis Ele.me kelihatan mudah, tetapi ia membingungkan ramai orang Aug 24, 2023 pm 03:29 PM

Jangan memandang rendah soalan peperiksaan bertulis banyak syarikat Terdapat perangkap dan anda boleh jatuh ke dalamnya secara tidak sengaja. Apabila anda menghadapi soalan ujian bertulis seperti ini tentang kitaran, saya cadangkan anda berfikir dengan tenang dan ambil langkah demi langkah.

5 Rentetan soalan temuduga, kurang daripada 10% orang boleh menjawab semuanya dengan betul! (dengan jawapan) 5 Rentetan soalan temuduga, kurang daripada 10% orang boleh menjawab semuanya dengan betul! (dengan jawapan) Aug 23, 2023 pm 02:49 PM

Artikel ini akan melihat 5 soalan temu bual tentang kelas Java String Saya sendiri telah mengalami beberapa daripada lima soalan ini semasa proses temu duga.

Adalah disyorkan untuk mengumpul 100 soalan temuduga Linux dengan jawapan Adalah disyorkan untuk mengumpul 100 soalan temuduga Linux dengan jawapan Aug 23, 2023 pm 02:37 PM

Artikel ini mempunyai jumlah lebih daripada 30,000 perkataan, meliputi gambaran keseluruhan Linux, cakera, direktori, fail, keselamatan, tahap sintaks, pertempuran praktikal, arahan pengurusan fail, arahan penyuntingan dokumen, arahan pengurusan cakera, arahan komunikasi rangkaian, arahan pengurusan sistem, sandaran arahan mampatan, dsb. Membongkar mata pengetahuan Linux.

Meituan, lihat adakah anda boleh menjawabnya? Meituan, lihat adakah anda boleh menjawabnya? Aug 24, 2023 pm 03:51 PM

Meituan, lihat adakah anda boleh menjawabnya?

See all articles