SpringBoot實(shí)現(xiàn)整合微信支付方法詳解
1.準(zhǔn)備工作
1.1 數(shù)據(jù)庫表
這里涉及微信支付一共兩個表:
訂單表
支付記錄表
1.2 實(shí)體類
數(shù)據(jù)庫對應(yīng)的實(shí)體類:
訂單表
@Data @ToString @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("t_order") @ApiModel(value = "Order對象", description = "訂單") public class Order implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.ID_WORKER_STR) private String id; @ApiModelProperty(value = "訂單號") private String orderNo; @ApiModelProperty(value = "課程id") private String courseId; @ApiModelProperty(value = "課程名稱") private String courseTitle; @ApiModelProperty(value = "課程封面") private String courseCover; @ApiModelProperty(value = "講師名稱") private String teacherName; @ApiModelProperty(value = "會員id") private String memberId; @ApiModelProperty(value = "會員昵稱") private String nickname; @ApiModelProperty(value = "會員手機(jī)") private String mobile; @ApiModelProperty(value = "訂單金額(分)") private BigDecimal totalFee; @ApiModelProperty(value = "支付類型(1:微信 2:支付寶)") private Integer payType; @ApiModelProperty(value = "訂單狀態(tài)(0:未支付 1:已支付)") private Integer status; @ApiModelProperty(value = "邏輯刪除 1(true)已刪除, 0(false)未刪除") private Boolean isDeleted; @ApiModelProperty(value = "創(chuàng)建時間") @TableField(fill = FieldFill.INSERT) private Date gmtCreate; @ApiModelProperty(value = "更新時間") @TableField(fill = FieldFill.INSERT_UPDATE) private Date gmtModified; }
支付日志表
@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("t_pay_log") @ApiModel(value = "PayLog對象", description = "支付日志表") public class PayLog implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.ID_WORKER_STR) private String id; @ApiModelProperty(value = "訂單號") private String orderNo; @ApiModelProperty(value = "支付完成時間") private Date payTime; @ApiModelProperty(value = "支付金額(分)") private BigDecimal totalFee; @ApiModelProperty(value = "交易流水號") private String transactionId; @ApiModelProperty(value = "交易狀態(tài)") private String tradeState; @ApiModelProperty(value = "支付類型(1:微信 2:支付寶)") private Integer payType; @ApiModelProperty(value = "其他屬性") private String attr; @ApiModelProperty(value = "邏輯刪除 1(true)已刪除, 0(false)未刪除") private Boolean isDeleted; @ApiModelProperty(value = "創(chuàng)建時間") @TableField(fill = FieldFill.INSERT) private Date gmtCreate; @ApiModelProperty(value = "更新時間") @TableField(fill = FieldFill.INSERT_UPDATE) private Date gmtModified; }
1.3 導(dǎo)入依賴
在訂單模塊service_order導(dǎo)入微信支付需要的依賴:
<dependencies> <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> </dependency> </dependencies>
1.4 配置文件
在配置文件application.properties配置相關(guān)的信息:
# 服務(wù)端口 server.port=8007 # 服務(wù)名 spring.application.name=service-order # mysql數(shù)據(jù)庫連接 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=root #返回json的全局時間格式 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GMT+8 #配置mapper xml文件的路徑 mybatis-plus.mapper-locations=classpath:com/atguigu/eduorder/mapper/xml/*.xml #mybatis日志 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl # nacos服務(wù)地址 spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 #開啟熔斷機(jī)制 #feign.hystrix.enabled=true # 設(shè)置hystrix超時時間,默認(rèn)1000ms #hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000 #關(guān)聯(lián)的公眾號appid wx.pay.app_id=wx74862e0dfc69954 #商戶號 wx.pay.partner=155895011 #商戶key wx.pay.partnerkey=T6m9iK73b0kn9g5v426MKHQH7X8rKwb #回調(diào)地址 wx.pay.notifyurl=http://guli.shop/api/order/weixinPay/weixinNotify #微信提供的固定地址 wx.pay.wxurl=https://api.mch.weixin.qq.com/pay/unifiedorder #微信查詢狀態(tài)地址 wx.pay.queryUrl=https://api.mch.weixin.qq.com/pay/orderquery
1.5 創(chuàng)建讀取微信支付相關(guān)信息的工具類
創(chuàng)建一個讀取微信支付需要的信息的工具類ConstantWxPayUtils:
@Controller public class ConstantWxPayUtils implements InitializingBean { @Value("${wx.pay.app_id}") private String appID; @Value("${wx.pay.partner}") private String partner; @Value("${wx.pay.partnerkey}") private String partnerKey; @Value("${wx.pay.notifyurl}") private String notifyUrl; @Value("${wx.pay.wxurl}") private String wxUrl; @Value("${wx.pay.queryUrl}") private String queryUrl; //定義公共靜態(tài)常量 public static String WX_PAY_APP_ID; public static String WX_PAY_PARTNER; public static String WX_PAY_PARTNER_KEY; public static String WX_PAY_NOTIFY_URL; public static String WX_PAY_WX_URL; public static String WX_PAY_QUERY_URL; @Override public void afterPropertiesSet() throws Exception { WX_PAY_APP_ID = appID; WX_PAY_PARTNER = partner; WX_PAY_PARTNER_KEY = partnerKey; WX_PAY_NOTIFY_URL = notifyUrl; WX_PAY_WX_URL = wxUrl; WX_PAY_QUERY_URL=queryUrl; } }
1.6 其他工具類
用于隨機(jī)生成訂單號的工具類OrderNoUtil:
public class OrderNoUtil { /** * 獲取訂單號 * @return */ public static String getOrderNo() { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String newDate = sdf.format(new Date()); String result = ""; Random random = new Random(); for (int i = 0; i < 3; i++) { result += random.nextInt(10); } return newDate + result; } }
HttpClient工具類:
/** * http請求客戶端 * * @author xppll * */ public class HttpClient { private String url; private Map<String, String> param; private int statusCode; private String content; private String xmlParam; private boolean isHttps; public boolean isHttps() { return isHttps; } public void setHttps(boolean isHttps) { this.isHttps = isHttps; } public String getXmlParam() { return xmlParam; } public void setXmlParam(String xmlParam) { this.xmlParam = xmlParam; } public HttpClient(String url, Map<String, String> param) { this.url = url; this.param = param; } public HttpClient(String url) { this.url = url; } public void setParameter(Map<String, String> map) { param = map; } public void addParameter(String key, String value) { if (param == null) param = new HashMap<String, String>(); param.put(key, value); } public void post() throws ClientProtocolException, IOException { HttpPost http = new HttpPost(url); setEntity(http); execute(http); } public void put() throws ClientProtocolException, IOException { HttpPut http = new HttpPut(url); setEntity(http); execute(http); } public void get() throws ClientProtocolException, IOException { if (param != null) { StringBuilder url = new StringBuilder(this.url); boolean isFirst = true; for (String key : param.keySet()) { if (isFirst) url.append("?"); else url.append("&"); url.append(key).append("=").append(param.get(key)); } this.url = url.toString(); } HttpGet http = new HttpGet(url); execute(http); } /** * set http post,put param */ private void setEntity(HttpEntityEnclosingRequestBase http) { if (param != null) { List<NameValuePair> nvps = new LinkedList<NameValuePair>(); for (String key : param.keySet()) nvps.add(new BasicNameValuePair(key, param.get(key))); // 參數(shù) http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 設(shè)置參數(shù) } if (xmlParam != null) { http.setEntity(new StringEntity(xmlParam, Consts.UTF_8)); } } private void execute(HttpUriRequest http) throws ClientProtocolException, IOException { CloseableHttpClient httpClient = null; try { if (isHttps) { SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial(null, new TrustStrategy() { // 信任所有 public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslContext); httpClient = HttpClients.custom().setSSLSocketFactory(sslsf) .build(); } else { httpClient = HttpClients.createDefault(); } CloseableHttpResponse response = httpClient.execute(http); try { if (response != null) { if (response.getStatusLine() != null) statusCode = response.getStatusLine().getStatusCode(); HttpEntity entity = response.getEntity(); // 響應(yīng)內(nèi)容 content = EntityUtils.toString(entity, Consts.UTF_8); } } finally { response.close(); } } catch (Exception e) { e.printStackTrace(); } finally { httpClient.close(); } } public int getStatusCode() { return statusCode; } public String getContent() throws ParseException, IOException { return content; } }
2.生成訂單
這里一共涉及service_order訂單模塊、service_ucenter用戶模塊、service-edu課程模塊。
service_order使用Fegin遠(yuǎn)程調(diào)用其他模塊的方法。
詳細(xì)的Fegin的使用可以參考:SpringCloud-Feign遠(yuǎn)程調(diào)用
2.1 遠(yuǎn)程調(diào)用用戶模塊和課程模塊
在service_order訂單模塊創(chuàng)建:
@Component @FeignClient("service-ucenter") //調(diào)用的服務(wù)名稱 public interface UcenterClient { //根據(jù)用戶id獲取用戶信息,用于生成訂單使用 @PostMapping("/educenter/member/getUserInfoOrder/{id}") public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id); }
@Component @FeignClient("service-edu") //調(diào)用的服務(wù)名稱 public interface CourseClient { //根據(jù)課程id查詢課程信息 @PostMapping("/eduservice/coursefront/getCourseInfoOrder/{id}") public CourseWebOrder getCourseInfoOrder(@PathVariable("id") String id); }
2.2 遠(yuǎn)程調(diào)用方法的實(shí)現(xiàn)
在service-edu課程模塊實(shí)現(xiàn)根據(jù)課程id查詢課程信息的getCourseInfoOrder方法
controller層:
/** * 根據(jù)課程id查詢課程信息 * @param id 客場id * @return CourseWebOrder */ @PostMapping("getCourseInfoOrder/{id}") public CourseWebOrder getCourseInfoOrder(@PathVariable("id") String id) { CourseWebVo courseInfo = courseService.getBaseCourseInfo(id); CourseWebOrder courseWebOrder = new CourseWebOrder(); BeanUtils.copyProperties(courseInfo, courseWebOrder); return courseWebOrder; }
service層:
/** * 根據(jù)課程id,編寫sql語句查詢課程信息 * @param courseId 課程id * @return CourseWebVo */ @Override public CourseWebVo getBaseCourseInfo(String courseId) { return baseMapper.getBaseCourseInfo(courseId); }
mapper層:
<!--根據(jù)課程id查詢課程基本信息--> <select id="getBaseCourseInfo" resultType="com.atguigu.eduservice.entity.frontvo.CourseWebVo"> SELECT ec.id, ec.`title`, ec.`price`, ec.lesson_num as lessonNum, ec.cover, ec.buy_count as buyCount, ec.view_count as viewCount, ecd.description, et.id teacherId, et.`name` AS teacherName, et.intro, et.avatar, es1.id as subjectLevelOneId, es1.`title` AS subjectLevelOne, es2.id as subjectLevelTwoId, es2.`title` AS subjectLevelTwo FROM edu_course ec LEFT JOIN edu_course_description ecd ON ec.id = ecd.id LEFT JOIN edu_teacher et ON ec.`teacher_id` = et.`id` LEFT JOIN edu_subject es1 ON ec.`subject_parent_id` = es1.`id` LEFT JOIN edu_subject es2 ON ec.`subject_id` = es2.`id` WHERE ec.id = #{courseId} </select>
在service_ucenter用戶模塊實(shí)現(xiàn)根據(jù)用戶id獲取用戶信息的getUserInfoOrder方法
controller層:
/** * 根據(jù)用戶id獲取用戶信息,用于生成訂單使用 * * @param id 用戶id * @return UcenterMemberOrder */ @PostMapping("getUserInfoOrder/{id}") public UcenterMemberOrder getUserInfoOrder(@PathVariable("id") String id) { UcenterMember member = memberService.getById(id); UcenterMemberOrder memberOrder = new UcenterMemberOrder(); BeanUtils.copyProperties(member, memberOrder); return memberOrder; }
2.3 根據(jù)課程id和用戶id生成訂單
controller層:
@CrossOrigin @RestController @RequestMapping("/eduorder/order") public class OrderController { @Autowired private OrderService orderService; /** * 生成訂單的方法 * * @param courseId 課程id * @param request 用于獲取用戶id * @return 返回訂單號 */ @PostMapping("createOrder/{courseId}") public R saveOrder(@PathVariable("courseId") String courseId, HttpServletRequest request) { //通過JWT工具類獲取用戶id //創(chuàng)建訂單,返回訂單號 String orderNo = orderService.createOrderById(courseId, JwtUtils.getMemberIdByJwtToken(request)); return R.ok().data("orderId", orderNo); } }
service層:
/** * 根據(jù)courseId和userId生成訂單 * * @param courseId 課程id * @param userId 用戶id * @return 返回訂單號 */ @Override public String createOrderById(String courseId, String userId) { //通過遠(yuǎn)程調(diào)傭根據(jù)用戶id獲取用戶信息 UcenterMemberOrder userInfoOrder = ucenterClient.getUserInfoOrder(userId); //通過遠(yuǎn)程調(diào)傭根據(jù)課程id獲取課程信息 CourseWebOrder courseInfoOrder = courseClient.getCourseInfoOrder(courseId); Order order = new Order(); //訂單號 order.setOrderNo(OrderNoUtil.getOrderNo()); order.setCourseId(courseId); order.setCourseTitle(courseInfoOrder.getTitle()); order.setCourseCover(courseInfoOrder.getCover()); order.setTeacherName(courseInfoOrder.getTeacherName()); order.setTotalFee(courseInfoOrder.getPrice()); order.setMemberId(userId); order.setMobile(userInfoOrder.getMobile()); order.setNickname(userInfoOrder.getNickname()); //支付狀態(tài) 未支付:0 已支付:1 order.setStatus(0); //支付類型 微信:1 支付寶:2 order.setPayType(1); //保存到數(shù)據(jù)庫 baseMapper.insert(order); //返回訂單號 return order.getOrderNo(); }
3.查詢訂單信息
3.1 controller層
在OrderController里創(chuàng)建getOrderInfo用于生成訂單:
/** * 根據(jù)訂單id查詢訂單信息 * @param orderId 訂單id * @return 返回訂單信息 */ @GetMapping("getOrderInfo/{orderId}") public R getOrderInfo(@PathVariable("orderId") String orderId) { Order order=orderService.getOrderByOrderId(orderId); return R.ok().data("item", order); }
3.2 service層
/** * 根據(jù)訂單id查詢訂單信息 * * @param orderId 訂單id * @return 返回訂單信息 */ @Override public Order getOrderByOrderId(String orderId) { LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Order::getOrderNo, orderId); return baseMapper.selectOne(queryWrapper); }
4.生成微信支付的二維碼
4.1 controller層
在PayLogController里創(chuàng)建createNative用于生成支付二維碼:
@CrossOrigin @RestController @RequestMapping("/eduorder/paylog") public class PayLogController { @Autowired private PayLogService payLogService; /** * 根據(jù)訂單號生成微信支付二維碼 * @param orderNo 訂單號 * @return R */ @GetMapping("createNative/{orderNo}") public R createNative(@PathVariable("orderNo") String orderNo){ //返回信息,包含二維碼地址,還有其他信息 Map map=payLogService.createNative(orderNo); return R.ok().data(map); } }
4.2 service層
- 生成微信支付二維碼大概分為這幾步:
- 根據(jù)訂單號查詢訂單信息
- 使用map設(shè)置生成二維碼需要的參數(shù)
- 發(fā)送httpclient請求,傳遞xml格式的參數(shù),傳入微信支付提供的固定地址
- 得到發(fā)送請求返回的結(jié)果
- 最終返回封裝數(shù)據(jù)
/** * 根據(jù)訂單號生成微信支付二維碼 * @param orderNo 訂單號 * @return map */ @Override public Map createNative(String orderNo) { try { //1.根據(jù)訂單號查詢訂單信息 Order order = orderService.getOrderByOrderId(orderNo); //2.使用map設(shè)置生成二維碼需要的參數(shù) Map m = new HashMap(); //關(guān)聯(lián)的公眾號appid m.put("appid", ConstantWxPayUtils.WX_PAY_APP_ID); //商戶號 m.put("mch_id", ConstantWxPayUtils.WX_PAY_PARTNER); //隨機(jī)字符串 m.put("nonce_str", WXPayUtil.generateNonceStr()); //課程標(biāo)題 m.put("body", order.getCourseTitle()); //訂單號 m.put("out_trade_no", orderNo); //價格 m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue() + ""); //支付的ip地址 m.put("spbill_create_ip", "127.0.0.1"); m.put("notify_url", ConstantWxPayUtils.WX_PAY_NOTIFY_URL); m.put("trade_type", "NATIVE"); //3.發(fā)送httpclient請求,傳遞參數(shù)xml格式,傳入微信支付提供的固定地址 HttpClient client = new HttpClient(ConstantWxPayUtils.WX_PAY_WX_URL); //設(shè)置xml格式的參數(shù),需要傳入二維碼參數(shù)m和商戶key client.setXmlParam(WXPayUtil.generateSignedXml(m, ConstantWxPayUtils.WX_PAY_PARTNER_KEY)); //默認(rèn)不支持https,設(shè)置為true支持 client.setHttps(true); //執(zhí)行請求發(fā)送 client.post(); //4.得到發(fā)送請求返回的結(jié)果 //返回的內(nèi)容是xml格式 String xml = client.getContent(); //把xml格式轉(zhuǎn)換為map集合 Map<String, String> resultMap = WXPayUtil.xmlToMap(xml); //5.最終返回封裝數(shù)據(jù) Map map = new HashMap(); //訂單號 map.put("out_trade_no", orderNo); //課程id map.put("course_id", order.getCourseId()); //價格 map.put("total_fee", order.getTotalFee()); //返回二維碼操作狀態(tài)碼 map.put("result_code", resultMap.get("result_code")); //二維碼地址 map.put("code_url", resultMap.get("code_url")); return map; } catch (Exception e) { throw new GuliException(20001, "生成微信支付二維碼失敗"); } }
5.查詢訂單支付狀態(tài)
5.1 controller層
在PayLogController里創(chuàng)建queryPayStatus用于獲取支付狀態(tài):
/** * 獲取支付狀態(tài) * @param orderNo 訂單號 * @return R */ @GetMapping("queryPayStatus/{orderNo}") public R queryPayStatus(@PathVariable("orderNo") String orderNo){ Map<String, String> map=payLogService.queryPayStatus(orderNo); if(map==null){ return R.error().message("支付出錯!"); } //如果map不為空,通過map獲取訂單狀態(tài) if(map.get("trade_state").equals("SUCCESS")){ //添加記錄到支付表,更新訂單表訂單狀態(tài) payLogService.updateOrdersStatus(map); return R.ok().message("支付成功!"); } return R.ok().code(25000).message("正在支付中..."); }
5.2 service層
根據(jù)訂單號查詢訂單支付狀態(tài)大概分為一下幾步:
- 封裝參數(shù)
- 發(fā)送httpclient
- 得到請求返回的內(nèi)容
/** * 根據(jù)訂單號查詢訂單支付狀態(tài) * @param orderNo * @return */ @Override public Map<String, String> queryPayStatus(String orderNo) { try { //1.封裝參數(shù) Map m=new HashMap(); //關(guān)聯(lián)的公眾號appid m.put("appid",ConstantWxPayUtils.WX_PAY_APP_ID); //商戶號 m.put("mch_id",ConstantWxPayUtils.WX_PAY_PARTNER); //訂單號 m.put("out_trade_no",orderNo); //隨機(jī)字符串 m.put("nonce_str",WXPayUtil.generateNonceStr()); //2.發(fā)送httpclient HttpClient client = new HttpClient(ConstantWxPayUtils.WX_PAY_QUERY_URL); client.setXmlParam(WXPayUtil.generateSignedXml(m,ConstantWxPayUtils.WX_PAY_PARTNER_KEY)); client.setHttps(true); client.post(); //3.得到請求返回的內(nèi)容 String xml = client.getContent(); Map<String, String> resultMap=WXPayUtil.xmlToMap(xml); return resultMap; } catch (Exception e) { e.printStackTrace(); throw new GuliException(20001,"查詢訂單支付狀態(tài)失敗"); } }
如果支付成功,需要添加記錄到支付表,更新訂單表訂單狀態(tài):
/**
* 向支付表添加記錄,更新訂單表訂單狀態(tài)
* @param map
*/
@Override
public void updateOrdersStatus(Map<String, String> map) {
//從map獲取訂單號
String orderNo = map.get("out_trade_no");
Order order = orderService.getOrderByOrderId(orderNo);
//更新訂單表t_order的訂單狀態(tài)status
if(order.getStatus().intValue()==1){
return;
}
order.setStatus(1);
orderService.updateById(order);
//向支付表 t_pag_log 添加記錄
PayLog payLog=new PayLog();
payLog.setOrderNo(orderNo);
payLog.setPayTime(new Date());
//支付類型
payLog.setPayType(1);
//支付金額
payLog.setTotalFee(order.getTotalFee());
//支付狀態(tài)
payLog.setTradeState(map.get("trade_state"));
//交易流水號
payLog.setTransactionId(map.get("transaction_id"));
//其他屬性,轉(zhuǎn)為json字符串
payLog.setAttr(JSONObject.toJSONString(map));
baseMapper.insert(payLog);
}
以上就是SpringBoot實(shí)現(xiàn)整合微信支付方法詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot整合微信支付的資料請關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot實(shí)現(xiàn)微信支付接口調(diào)用及回調(diào)函數(shù)(商戶參數(shù)獲取)
- java?Springboot對接開發(fā)微信支付詳細(xì)流程
- SpringBoot對接小程序微信支付的實(shí)現(xiàn)
- Springboot整合微信支付(訂單過期取消及商戶主動查單)
- UniApp?+?SpringBoot?實(shí)現(xiàn)微信支付和退款功能
- springboot對接微信支付的完整流程(附前后端代碼)
- 一篇文章帶你入門Springboot整合微信登錄與微信支付(附源碼)
- springboot整合微信支付sdk過程解析
- SpringBoot+MyBatis集成微信支付實(shí)現(xiàn)示例
相關(guān)文章
eclipse導(dǎo)入IntelliJ IDEA的maven項(xiàng)目的示例
本篇文章主要介紹了eclipse導(dǎo)入IntelliJ IDEA的maven項(xiàng)目的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12簡單實(shí)現(xiàn)Java web服務(wù)器
這篇文章主要為大家詳細(xì)介紹了簡單實(shí)現(xiàn)Java web服務(wù)器的詳細(xì)步驟,感興趣的小伙伴們可以參考一下2016-06-06MyBatis攔截器:給參數(shù)對象屬性賦值的實(shí)例
下面小編就為大家?guī)硪黄狹yBatis攔截器:給參數(shù)對象屬性賦值的實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04java中stringbuffer線程安全分析實(shí)例詳解
在本篇文章里小編給大家整理的是一篇關(guān)于java中stringbuffer線程安全分析實(shí)例詳解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2021-01-01Java中的Random和ThreadLocalRandom詳細(xì)解析
這篇文章主要介紹了Java中的Random和ThreadLocalRandom詳細(xì)解析,Random 類用于生成偽隨機(jī)數(shù)的流, 該類使用48位種子,其使用線性同余公式進(jìn)行修改,需要的朋友可以參考下2024-01-01