一、注册阿里云账号并开通OSS服务

1、登录阿里云账号



2、创建一个bucket



3、创建子用户



对自用户分配权限,打开操作OSS的全部权限(也可根据业务需求进行更改)



4、配置上传跨域规则

  • 任何来源: *
  • 允许方法: POST
  • 任何请求头Headers: *

二、文件上传方式

1、服务器直传方式

每个OSS的用户都会用到上传服务。Web端常见的上传方法是用户在浏览器或App端上传文件到应用服务器,应用服务器再把文件上传到OSS

和数据直传到OSS相比,以上方法有三个缺点:

  • 上传慢:用户数据需先上传到到应用服务器,之后再上传到OSS。网络传输时间比直传到OSS多一倍。如果用于数据不通过应用服务器中转,而是直传到OSS,速度将大大提升。而且OSS采用BGP带宽,能保证各地各运营商之间的传输速度
  • 扩展性差:如果后续用户多了,应用服务器会成为瓶颈
  • 费用高:需要准备多台应用服务器。由于OSS上传流量是免费的,如果数据直传到OSS,不通过应用服务器,那么将能省下几台应用服务器

2、服务端签名后前端直传

Web前端服务端请求签名,然后前端(Vue)直接上传,不会对服务端产生压力,而且安全可靠。

相关资料:服务端签名直传并设置上传回调概述

Java连接实例:Java实践OSS

上传回调流程

  1. Web前端请求应用服务器,获取上传所需参数(如OSS的accessKeyId、policy、callback等参数)
  2. 应用服务器返回相关参数
  3. Web前端直接向OSS服务发起上传文件请求
  4. 等上传完成后OSS服务会回调应用服务器的回调接口
  5. 应用服务器返回响应给OSS服务
  6. OSS服务将应用服务器回调接口的内容返回给Web前端

3、SpringBoot整合OSS实现文件上传

1、在pom.xml中添加相关依赖

  1. <dependency>
  2. <groupId>com.aliyun.oss</groupId>
  3. <artifactId>aliyun-sdk-oss</artifactId>
  4. <version>3.10.2</version>
  5. </dependency>

2、修改SpringBoot配置文件

  1. #操作oss需要的一些参数
  2. aliyun:
  3. oss:
  4. accessKeyId: xxx # 阿里云的accessKeyId
  5. accessKeySecret: xxx # accessKey 密码
  6. endPoint: xxx # Endpoint:在阿里云oss控制台查看自己使用的endpoint,eg: oss-cn-shanghai.aliyuncs.com
  7. bucketName: xxx # bucket 名称
  8. policy:
  9. expire: 300 # 签名有效期(S)
  10. maxSize: 10 # 上传文件大小(M)
  11. callback: http://localhost:8080/aliyun/oss/callback # 文件上传成功后的回调地址
  12. dir:
  13. prefix: xxx/images/ # 上传文件夹路径前缀

3、添加OSS的相关Java配置

用于配置OSS的连接客户端的OSSClient

  1. /**
  2. * TODO 用于配置OSS的连接客户端OSSClient
  3. *
  4. * @author ss_419
  5. * @version 1.0
  6. * @date 2023/5/28 19:04
  7. */
  8. @Configuration
  9. @Component
  10. public class OssConfig {
  11. @Value("${aliyun.oss.endpoint}")
  12. private String ALIYUN_OSS_ENDPOINT;
  13. @Value("${aliyun.oss.accessKeyId}")
  14. private String ALIYUN_OSS_ACCESSKEYID;
  15. @Value("${aliyun.oss.accessKeySecret}")
  16. private String ALIYUN_OSS_ACCESSKEYSECRET;
  17. @Bean
  18. public OSSClient ossClient() {
  19. return new OSSClient(ALIYUN_OSS_ENDPOINT, ALIYUN_OSS_ACCESSKEYID, ALIYUN_OSS_ACCESSKEYSECRET);
  20. }
  21. }

4、封装前端上传策略返回对象

前端直传时所需要的参数

  1. package org.pp.oss.model;
  2. /**
  3. * TODO 获取OSS上传文件授权返回结果
  4. *
  5. * @author ss_419
  6. * @version 1.0
  7. * @date 2023/5/28 19:07
  8. */
  9. public class OssPolicyResult {
  10. private String accessKeyId;
  11. // @ApiModelProperty("用户表单上传的策略,经过base64编码过的字符串") 13
  12. private String policy;
  13. // @ApiModelProperty("对policy签名后的字符串") 15
  14. private String signature;
  15. // @ApiModelProperty("上传文件夹路径前缀") 17
  16. private String dir;
  17. // @ApiModelProperty("oss对外服务的访问域名") 19
  18. private String host;
  19. // @ApiModelProperty("上传成功后的回调设置")
  20. private String callback;
  21. // 忽略getter、setter方法
  22. }

5、封装上传成功回调参数对象

当OSS上传成功后,会根据该配置参数来回调对应接口

  1. package org.pp.oss.model;
  2. /**
  3. * TODO oss上传成功后的回调参数
  4. *
  5. * @author ss_419
  6. * @version 1.0
  7. * @date 2023/5/28 19:10
  8. */
  9. public class OssCallbackParam {
  10. //请求的回调地址
  11. private String callbackUrl;
  12. //回调是传入request中的参数
  13. private String callbackBody;
  14. //回调时传入参数的格式,比如表单提交形式
  15. private String callbackBodyType;
  16. public String getCallbackUrl() {
  17. return callbackUrl;
  18. }
  19. public void setCallbackUrl(String callbackUrl) {
  20. this.callbackUrl = callbackUrl;
  21. }
  22. public String getCallbackBody() {
  23. return callbackBody;
  24. }
  25. public void setCallbackBody(String callbackBody) {
  26. this.callbackBody = callbackBody;
  27. }
  28. public String getCallbackBodyType() {
  29. return callbackBodyType;
  30. }
  31. public void setCallbackBodyType(String callbackBodyType) {
  32. this.callbackBodyType = callbackBodyType;
  33. }
  34. }

6、封装上传成功后回调结果对象

回调接口中返回的数据对象,封装了上传文件的信息

  1. /**
  2. * TODO oss上传文件的回调结果
  3. *
  4. * @author ss_419
  5. * @version 1.0
  6. * @date 2023/5/28 19:14
  7. */
  8. public class OssCallbackResult {
  9. private String filename;// 文件名称
  10. private String size;// 文件大小
  11. private String mimeType;// 文件的mimeType
  12. private String width;// 图片文件的宽
  13. private String height;// 图片文件的高
  14. // 忽略getter、setter方法
  15. }

7、添加OSS业务接口OssService

  1. /**
  2. * TODO oss上传管理Service
  3. *
  4. * @author ss_419
  5. * @version 1.0
  6. * @date 2023/5/28 19:16
  7. */
  8. public interface OssService {
  9. /**
  10. * oss上传策略生成
  11. * @return
  12. */
  13. OssPolicyResult policy();
  14. /**
  15. * oss上传成功回调
  16. * @param request
  17. * @return
  18. */
  19. OssCallbackResult callback(HttpServletRequest request);
  20. }

8、OssService实现类

  1. package org.pp.oss.service.impl;/*
  2. package org.pp.oss.service.impl;
  3. import org.pp.oss.model.OssCallbackResult;
  4. import org.pp.oss.model.OssPolicyResult;
  5. import org.pp.oss.service.OssService;
  6. import javax.servlet.http.HttpServletRequest;
  7. */
  8. import cn.hutool.json.JSONUtil;
  9. import com.aliyun.oss.OSSClient;
  10. import com.aliyun.oss.common.utils.BinaryUtil;
  11. import com.aliyun.oss.model.MatchMode;
  12. import com.aliyun.oss.model.PolicyConditions;
  13. import org.pp.oss.model.OssCallbackParam;
  14. import org.pp.oss.model.OssCallbackResult;
  15. import org.pp.oss.model.OssPolicyResult;
  16. import org.pp.oss.service.OssService;
  17. import org.slf4j.Logger;
  18. import org.slf4j.LoggerFactory;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.beans.factory.annotation.Value;
  21. import org.springframework.stereotype.Service;
  22. import javax.servlet.http.HttpServletRequest;
  23. import java.text.SimpleDateFormat;
  24. import java.util.Date;
  25. /**
  26. * TODO
  27. *
  28. * @author ss_419
  29. * @version 1.0
  30. * @date 2023/5/28 19:17
  31. */
  32. @Service
  33. public class OssServiceImpl implements OssService {
  34. private static final Logger LOGGER = LoggerFactory.getLogger(OssServiceImpl.class);
  35. @Value("${aliyun.oss.policy.expire}")
  36. private int ALIYUN_OSS_EXPIRE;
  37. @Value("${aliyun.oss.maxSize}")
  38. private int ALIYUN_OSS_MAX_SIZE;
  39. @Value("${aliyun.oss.callback}")
  40. private String ALIYUN_OSS_CALLBACK;
  41. @Value("${aliyun.oss.bucketName}")
  42. private String ALIYUN_OSS_BUCKET_NAME;
  43. @Value("${aliyun.oss.endpoint}")
  44. private String ALIYUN_OSS_ENDPOINT;
  45. @Value("${aliyun.oss.dir.prefix}")
  46. private String ALIYUN_OSS_DIR_PREFIX;
  47. @Autowired
  48. private OSSClient ossClient;
  49. /**
  50. * 签名生成
  51. *
  52. * @return
  53. */
  54. @Override
  55. public OssPolicyResult policy() {
  56. OssPolicyResult result = new OssPolicyResult();
  57. // 存储目录
  58. SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
  59. String baseDir = ALIYUN_OSS_DIR_PREFIX + sdf.format(new Date());
  60. // 签名有效期
  61. long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;
  62. Date expiration = new Date(expireEndTime);
  63. // 文件大小
  64. long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 *1024;
  65. // 回调地址
  66. OssCallbackParam callback = new OssCallbackParam();
  67. callback.setCallbackUrl(ALIYUN_OSS_CALLBACK);
  68. callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
  69. callback.setCallbackBody("application/x-www-form-urlencoded");
  70. // 提交节点
  71. String action = "https://" + ALIYUN_OSS_BUCKET_NAME + "." + ALIYUN_OSS_ENDPOINT;
  72. try {
  73. PolicyConditions policyConds = new PolicyConditions();
  74. policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,0,maxSize);
  75. policyConds.addConditionItem(MatchMode.StartWith,PolicyConditions.COND_KEY, baseDir);
  76. String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
  77. byte[] binaryData = postPolicy.getBytes("utf-8");
  78. String policy = BinaryUtil.toBase64String(binaryData);
  79. String signature = ossClient.calculatePostSignature(postPolicy);
  80. String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes("UTF-8"));
  81. // 返回结果
  82. result.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());
  83. result.setPolicy(policy);
  84. result.setSignature(signature);
  85. result.setDir(baseDir);
  86. result.setCallback(callbackData);
  87. result.setHost(action);
  88. } catch (Exception e) {
  89. LOGGER.error("签名生成失败{e}", e);
  90. }
  91. return result;
  92. }
  93. @Override
  94. public OssCallbackResult callback(HttpServletRequest request) {
  95. OssCallbackResult result = new OssCallbackResult();
  96. String filename = request.getParameter("filename");
  97. filename = "http://".concat(ALIYUN_OSS_BUCKET_NAME).concat(".").concat(ALIYUN_OSS_ENDPOINT).concat("/").concat(filename);
  98. result.setFilename(filename);
  99. result.setSize(request.getParameter("size"));
  100. result.setMimeType(request.getParameter("mimeType"));
  101. result.setHeight(request.getParameter("height"));
  102. result.setWidth(request.getParameter("width"));
  103. return result;
  104. }
  105. }

9、定义OssController接口

  1. package org.pp.oss.controller;
  2. import cn.hutool.json.JSONObject;
  3. import com.aliyun.oss.OSS;
  4. import com.aliyun.oss.OSSClientBuilder;
  5. import com.aliyun.oss.common.utils.BinaryUtil;
  6. import com.aliyun.oss.model.MatchMode;
  7. import com.aliyun.oss.model.PolicyConditions;
  8. import org.pp.oss.model.OssCallbackResult;
  9. import org.pp.oss.model.OssPolicyResult;
  10. import org.pp.oss.service.OssService;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.web.bind.annotation.CrossOrigin;
  13. import org.springframework.web.bind.annotation.RequestMapping;
  14. import org.springframework.web.bind.annotation.RestController;
  15. import javax.servlet.http.HttpServletRequest;
  16. import java.text.SimpleDateFormat;
  17. import java.util.Date;
  18. import java.util.LinkedHashMap;
  19. import java.util.Map;
  20. /**
  21. * TODO Oss相关操作接口
  22. *
  23. * @author ss_419
  24. * @version 1.0
  25. * @date 2023/5/28 20:43
  26. */
  27. @RestController
  28. @RequestMapping("/aliyun/oss")
  29. @CrossOrigin
  30. public class AliyunOssController {
  31. @Autowired
  32. private OssService ossService;
  33. @CrossOrigin
  34. @RequestMapping("/policys")
  35. public Map<String,String> policysMap(){
  36. // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
  37. String accessId = "xxx";
  38. String accessKey = "xxx";
  39. // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
  40. String endpoint = "oss-cn-shanghai.aliyuncs.com";
  41. // 填写Bucket名称,例如examplebucket。
  42. String bucket = "xxx";
  43. // 填写Host地址,格式为https://bucketname.endpoint。
  44. String host = "https://" + bucket + "."+ endpoint;
  45. // 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。
  46. // String callbackUrl = "https://192.168.0.0:8888";
  47. // 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
  48. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  49. String formatData = dateFormat.format(new Date());
  50. String dir = "osstest/"+formatData+ "/";
  51. // 创建ossClient实例。
  52. OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
  53. try {
  54. long expireTime = 30;
  55. long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
  56. Date expiration = new Date(expireEndTime);
  57. PolicyConditions policyConds = new PolicyConditions();
  58. policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
  59. policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
  60. String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
  61. byte[] binaryData = postPolicy.getBytes("utf-8");
  62. String encodedPolicy = BinaryUtil.toBase64String(binaryData);
  63. String postSignature = ossClient.calculatePostSignature(postPolicy);
  64. Map<String, String> respMap = new LinkedHashMap<String, String>();
  65. respMap.put("accessId", accessId);
  66. respMap.put("policy", encodedPolicy);
  67. respMap.put("signature", postSignature);
  68. respMap.put("dir", dir);
  69. respMap.put("host", host);
  70. respMap.put("expire", String.valueOf(expireEndTime / 1000));
  71. return respMap;
  72. // respMap.put("expire", formatISO8601Date(expiration));
  73. // 回调数据
  74. // JSONObject jasonCallback = new JSONObject();
  75. // jasonCallback.put("callbackUrl", callbackUrl);
  76. // jasonCallback.put("callbackBody",
  77. // "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
  78. // jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
  79. // String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
  80. // respMap.put("callback", base64CallbackBody);
  81. //
  82. // JSONObject ja1 = JSONObject.fromObject(respMap);
  83. // // System.out.println(ja1.toString());
  84. // response.setHeader("Access-Control-Allow-Origin", "*");
  85. // response.setHeader("Access-Control-Allow-Methods", "GET, POST");
  86. // response(request, response, ja1.toString());
  87. } catch (Exception e) {
  88. // Assert.fail(e.getMessage());
  89. System.out.println(e.getMessage());
  90. }
  91. return null;
  92. }
  93. /**
  94. * oss上传签名生成
  95. * @return
  96. */
  97. @CrossOrigin
  98. @RequestMapping("/policy")
  99. public OssPolicyResult policy(){
  100. OssPolicyResult result = ossService.policy();
  101. System.out.println("result = " + result);
  102. return result;
  103. }
  104. /**
  105. * oss上传成功回调
  106. * @return
  107. */
  108. @RequestMapping("/callback")
  109. public OssCallbackResult callback(HttpServletRequest request){
  110. OssCallbackResult callback = ossService.callback(request);
  111. System.out.println("callback = " + callback);
  112. return callback;
  113. }
  114. }

对接口进行测试,如下图所示,请求返回了oss文件上传时所需的对应参数

4、Vue文件上传测试代码

这里为了更加方便快捷的进行文件上传接口的测试,我选择使用Vue+Element-Ui来搭建一个简单的上传案例

1、创建Vue项目

在控制台中输入vue ui,启动vue项目图形管理界面



访问http://localhost:8000 ,进入如下图操作界面即代表启动成功



找到项目管理器,创建一个新Vue项目

这里选择Vue2版本



创建成功后添加本次案例所需要的依赖:

  • axios:用于对后端服务发起Ajax请求
  • element-ui:本案例使用到该ui组件库中的Upload,用于文件上传

    在Vue项目中的main.js中启用对应依赖
  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. import ElementUI from 'element-ui';
  4. import 'element-ui/lib/theme-chalk/index.css';
  5. import axios from "axios";
  6. import VueAxios from "vue-axios";
  7. import router from './router'
  8. import store from './store'
  9. Vue.config.productionTip = false
  10. // Vue.use(axios)
  11. Vue.use(VueAxios,axios)
  12. Vue.use(ElementUI);
  13. new Vue({
  14. router,
  15. store,
  16. render: function (h) { return h(App) }
  17. }).$mount('#app')

创建OssUpload组件,该组件可以在项目中引用

  1. <template>
  2. <el-upload
  3. class="upload-demo"
  4. :action="objData.host"
  5. :before-upload="ossPolicy"
  6. :data="objData"
  7. :file-list="fileList"
  8. list-type="picture">
  9. <el-button size="small" type="primary">点击上传</el-button>
  10. <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
  11. </el-upload>
  12. </template>
  13. <script>
  14. export default {
  15. data() {
  16. return {
  17. fileList: [],
  18. objData: {
  19. OSSAccessKeyId: '',
  20. policy: '',
  21. signature: '',
  22. key: '',
  23. host: '',
  24. dir: ''
  25. }
  26. };
  27. },
  28. methods: {
  29. ossPolicy(file) {
  30. let _self = this;
  31. // 在上传前 进行服务器签名
  32. return new Promise((resolve, reject) => {
  33. this.axios.get("http://localhost:8080/aliyun/oss/policy")
  34. .then(response => {
  35. console.log(response)
  36. _self.objData.OSSAccessKeyId = response.data.accessKeyId
  37. _self.objData.policy = response.data.policy
  38. _self.objData.signature = response.data.signature
  39. _self.objData.dir = response.data.dir
  40. _self.objData.host = response.data.host+''
  41. _self.objData.key = response.data.dir + "${filename}"
  42. resolve(true) // 继续上传
  43. })
  44. .catch(error => {
  45. console.log(error)
  46. reject(false)
  47. })
  48. }
  49. )
  50. }
  51. }
  52. }
  53. </script>
  54. <style>
  55. </style>
  56. 在HelloWorld.vue中引用文件上传组件
  57. ```js
  58. <template>
  59. <div class="hello">
  60. <h1>{{ msg }}</h1>
  61. <OssUpload></OssUpload>
  62. </div>
  63. </template>
  64. <script>
  65. // 引用组件
  66. import OssUpload from "@/components/OssUpload.vue";
  67. export default {
  68. name: 'HelloWorld',
  69. components: {OssUpload},
  70. props: {
  71. msg: String
  72. }
  73. }
  74. </script>
  75. <style >
  76. </style>

前后端联调

  1. 启动后端服务

  2. 启动前端项目

选择文件进行上传,如下图所示即表示上传成功



查看对应的OSSBucket,图片已成功存储至OSS服务中

项目地址

SpringBoot整合OSS文件上传的更多相关文章

  1. 分布式文件系统FastDFS简介、搭建、与SpringBoot整合实现图片上传

    之前大学时搭建过一个FastDFS的图片服务器,当时只是抱着好奇的态度搭着玩一下,当时搭建采用了一台虚拟机,tracker和storage服务在一台机器上放着,最近翻之前的博客突然想着在两台机器上搭建 ...

  2. SpringBoot整合阿里云OSS文件上传、下载、查看、删除

    1. 开发前准备 1.1 前置知识 java基础以及SpringBoot简单基础知识即可. 1.2 环境参数 开发工具:IDEA 基础环境:Maven+JDK8 所用技术:SpringBoot.lom ...

  3. springboot整合vue实现上传下载文件

    https://blog.csdn.net/yhhyhhyhhyhh/article/details/89888953 文章目录 springboot整合vue实现上传下载文件 1上传下载文件api文 ...

  4. SpringBoot项目实现文件上传和邮件发送

    前言 本篇文章主要介绍的是SpringBoot项目实现文件上传和邮件发送的功能. SpringBoot 文件上传 说明:如果想直接获取工程那么可以直接跳到底部,通过链接下载工程代码. 开发准备 环境要 ...

  5. js实现oss文件上传及一些问题

    关于兼容性问题,ie8以下的可以使用4.x的版本 一.引入sdk和jq <script src="http://libs.baidu.com/jquery/2.0.0/jquery.m ...

  6. 构建基于阿里云OSS文件上传服务

    转载请注明来源:http://blog.csdn.net/loongshawn/article/details/50710132 <构建基于阿里云OSS文件上传服务> <构建基于OS ...

  7. OSS文件上传及OSS与ODPS之间数据连通

    场景描述        有这样一种场景,用户在自建服务器上存有一定数量级的CSV格式业务数据,某一天用户了解到阿里云的OSS服务存储性价比高(嘿嘿,颜值高),于是想将CSV数据迁移到云上OSS中,并且 ...

  8. PHP实现阿里云OSS文件上传(支持批量)

    上传文件至阿里云OSS,整体逻辑是,文件先临时上传到本地,然后在上传到OSS,最后删除本地的临时文件(也可以不删,具体看自己的业务需求),具体实现流程如下:   1.下载阿里云OSS对象上传SDK(P ...

  9. Springboot如何启用文件上传功能

    网上的文章在写 "springboot文件上传" 时,都让你加上模版引擎,我只想说,我用不上,加模版引擎,你是觉得我脑子坏了,还是觉得我拿不动刀了. springboot如何启用文 ...

  10. 记一次阿里云oss文件上传服务假死

    引言 记得以前刚开始学习web项目的时候,经常涉及到需要上传图片啥的,那时候都是把图片上传到当前项目文件夹下面,每次项目一重启图片就丢了.虽然可以通过修改/tomcat/conf/server.xml ...

随机推荐

  1. 基于.Net开发的、支持多平台、多语言餐厅点餐系统

    今天给大家推荐一套支持多平台.多语言版本的订单系统,适合餐厅.酒店等场景. 项目简介 这是基于.Net Framework开发的,支持手机.平板.PC等平台.多语言版本开源的点餐系统,非常适合餐厅.便 ...

  2. Centos 6 部署PPTP服务

    前言:PPTP使用一个TCP连接对隧道进行维护,使用通用路由封装(GRE)技术把数据封装成PPP数据桢通过隧道传送.可以对封装PPP桢中的负载数据进行加密或压缩. 注意:PPTP协议已经被IOS系统所 ...

  3. C#多线程开发-处理异步操作中的异常

    C#多线程开发-处理子线程中的异常 在平时的多线程开发中,对于异常的处理是至关重要的,千万不能马虎.如果在实际的项目中,对于某些线程中的异常没有处理,会直接导致整个程序崩溃,软件无法使用. 其中需要说 ...

  4. ASP.NET Core - 选项系统之选项使用

    上一篇 ASP.NET Core - 选项系统之选项配置 中提到 IOptions.IOptionsMonitor 和 IOptionsSnapshot 三个接口,通过这三个接口都可以从依赖注入容器中 ...

  5. 淘宝商品页面的爬取.py(亲测有效)

    import requests def getHTMLText(url): try: r = requests.get(url,timeout=30) r.raise_for_status() #如果 ...

  6. 2020寒假学习笔记14------Python基础语法学习(三)

    今天学习了Python的基础语法,其中学的内容有: 比较运算符.逻辑运算符.同一运算符.整数缓存问题.基本运算符.复合复制运算符.运算符优先级问题.字符串基本特点.字符串的编码.空字符串和len()函 ...

  7. AcWing 1902. 马拉松

    题目链接 每次路程改变只对前后两点间距离有影响,因此每次都判断当前三个点之间的距离之和与去掉中间点的距离哪个更优即可,最后取最大值作为结果输出. #include<iostream> #i ...

  8. 第三章3.1HTML技术与CSS技术

    web中的html以及css: html(超文本标记语言:Hyper Text Markup Language):用于描述网页的一种语言: 通常其根标签使用html标签:使用尖括号表示:<htm ...

  9. [Linux]CPU架构/指令集:RISC / CISC | arm | amd | X86/i386 | aarch64

    1 前言 本文是解决在软件开发.软件交付过程中,常常需要找寻与服务器硬件的CPU架构适配的软件包时,开发者和交付者又时常摸不着头脑.[迷迷糊糊]地就下载了某个所谓"适配".&quo ...

  10. LeeCode哈希问题(一)

    LeeCode 242: 有效的字母异位词 题目描述: 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词.若 s 和 t 中每个字符出现的次数都相同,则称互为字母异位词. ...