文章目录

  • ①. 品牌管理菜单
  • ②. 快速显示开关
  • ③. 阿里云上传概述
  • ④. 使用代码进行文件上传
  • ⑤. 结合Alibaba来管理oss
  • ⑥. gulimall-third-party微服务
  • ⑦. 服务端签名后直传
  • ⑧. 结合前端实现文件直传

①. 品牌管理菜单

  • ①. 后台:系统管理/菜单管理/新增

  • ②. 将逆向工程product得到的resources\src\views\modules\product文件拷贝到gulimall/renren-fast-vue/src/views/modules/product目录下’也就是下面的两个文件
    brand.vue : 显示的表单
    brand-add-or-update.vue:添加和更改功能

  • ③. 但是显示的页面没有新增和删除功能’这是因为权限控制的原因

<el-button v-if="isAuth('product:brand:save')" type="primary" @click="addOrUpdateHandle()">新增</el-button>
<el-button v-if="isAuth('product:brand:delete')" type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button>
  • ④. 查看“isAuth”的定义位置:将方法的返回值返回true,然后再次刷新页面(也可以将v-if注释掉)

  • ⑤. 注释掉检测语法
    build/webpack.base.conf.js 中注释掉createLintingRule()函数体’不进行lint语法检查

②. 快速显示开关

  • ①. 实现的效果如下
  • ②. 前台页面(参照elementui进行显示)
<el-table-columnprop="showStatus"header-align="center"align="center"label="显示状态"width="200"><template slot-scope="scope"><el-switchv-model="scope.row.showStatus"active-color="#13ce66"inactive-color="#ff4949":active-value="1":inactive-value="0"@change="updateBrandStatus(scope.row)"></el-switch></template>
</el-table-column>
//更新开关的状态
updateBrandStatus(data) {// 传入了改变行的数据console.log("最新状态", data);let { brandId, showStatus } = data;this.$http({url: this.$http.adornUrl("/product/brand/update"),method: "post",data: this.$http.adornData({ brandId, showStatus }, false)}).then(({ data }) => {this.$message({message: "状态更新成功",type: "success"});});
},
  • ③. 后台接口
@RestController
@RequestMapping("product/brand")
public class BrandController {/** * 修改 */@RequestMapping("/update")public R update(@RequestBody BrandEntity brand){brandService.updateById(brand);return R.ok();}
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {private static final long serialVersionUID = 1L;/* 品牌id */@TableIdprivate Long brandId;/*** 品牌名 */private String name;/*** 品牌logo地址 */private String logo;/*** 介绍 */private String descript;/*** 显示状态[0-不显示;1-显示]*/private Integer showStatus;/** * 检索首字母 */private String firstLetter;/** * 排序 */private Integer sort;
}
  • ④. 在新增或者修改的时候也要将按钮进行修改
    brand-add-or-update.vue
<el-form-item label="显示状态" prop="showStatus"><el-switch v-model="dataForm.showStatus"active-color="#13ce66"inactive-color="#ff4949":active-value="1":inactive-value="0"></el-switch>
</el-form-item>

③. 阿里云上传概述

  • ①. 阿里云上使使用对象存储方式:

  • ②. 创建Bucket,我们的Bucket名称叫 gulimall-tangzhi

  • ③. 上传文件:上传成功后’取得图片的URL
    这种方式是手动上传图片’实际上我们可以在程序中设置自动上传图片到阿里云对象存

  • ④. 我们后续将采用下面的方式进行图片的储存

④. 使用代码进行文件上传

  • ①. 简单文件上传OSS官方文档

  • ②. 添加依赖包,查看官方代码

<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.8.0</version>
</dependency>
// Endpoint以杭州为例'其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 云账号AccessKey有所有API访问权限'建议遵循阿里云安全最佳实践'创建并使用RAM子账号进行API访问或日常运维'请登录 https://ram.console.aliyun.com 创建。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);// 上传文件流。
InputStream inputStream = new FileInputStream("<yourlocalFile>");
ossClient.putObject("<yourBucketName>", "<yourObjectName>", inputStream);// 关闭OSSClient。
ossClient.shutdown();
 @Testpublic void upload()throws Exception{// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例'Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。String endpoint = "oss-cn-guangzhou.aliyuncs.com";// 阿里云账号AccessKey拥有所有API的访问权限'风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维'请登录RAM控制台创建RAM用户。String accessKeyId = "LTAI5t7E9sokgukBNzP45nX1";String accessKeySecret = "yKzdbTeQETI4u9okOAPDvSscEa5pVT";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);// 填写本地文件的完整路径。如果未指定本地路径'则默认从示例程序所属项目对应本地路径中上传文件流。InputStream inputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\car.jpg");// 依次填写Bucket名称(例如examplebucket)和Object完整路径(例如exampledir/exampleobject.txt)。Object完整路径中不能包含Bucket名称。ossClient.putObject("gulimall-tangzhi", "car.jpg", inputStream);// 关闭OSSClient。ossClient.shutdown();}

  • ③. endpoint指的是什么?
  • ④. accessKeyId和accessKeySecret指的是什么?

步骤
(1). accessKeyId和accessKeySecret需要创建一个RAM账号:

(2). 创建用户完毕后’会得到一个“AccessKey ID”和“AccessKeySecret”'然后复制这两个值到代码的“AccessKey ID”和“AccessKeySecret”。另外还需要添加访问控制权限:

  • ⑤. 我们在项目中使用的是SpringCloud Alibaba来管理oss,后续会进行介绍

⑤. 结合Alibaba来管理oss

  • ①. 使用SpringCloud Alibaba来管理oss

  • ②. 使用方式

  1. Add dependency aliyun-oss-spring-boot-starter in the pom.xml file in your Spring Boot project.
  2. Configure accessKeyId, secretAccessKey and region in application.properties.
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>aliyun-oss-spring-boot-starter</artifactId>
</dependency>
// application.properties
alibaba.cloud.access-key=your-ak
alibaba.cloud.secret-key=your-sk
alibaba.cloud.oss.endpoint=***
  • ③. 我们在common工程中引入oss的依赖

  • ④. 在product工程中进行测试

# DataSource Config
spring:cloud:alicloud:access-key: LTAI5t7E9sokgukBNzP45nX1secret-key: yKzdbTeQETI4u9okOAPDvSscEa5pVToss:endpoint: oss-cn-guangzhou.aliyuncs.com
@Resource
OSSClient ossClient;@Test
public void uploadCloudAlibaba()throws Exception{// 填写本地文件的完整路径。如果未指定本地路径'则默认从示例程序所属项目对应本地路径中上传文件流。InputStream inputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\car2.jpg");// 依次填写Bucket名称(例如examplebucket)和Object完整路径(例如exampledir/exampleobject.txt)。Object完整路径中不能包含Bucket名称。ossClient.putObject("gulimall-tangzhi", "car2.jpg", inputStream);
}

  • ⑤. 但是这样来做还是比较麻烦’如果以后的上传任务都交给gulimall-product来完成’显然耦合度高。最好单独新建一个Module来完成文件上传任务

⑥. gulimall-third-party微服务

  • ①. 环境配置如下
    因为在common工程中引入了mybatis-plus,我们这个gulimall-third-party服务将其依赖进行排除掉

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.8.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.atguigu.gulimall</groupId><artifactId>gulimall-third-party</artifactId><version>0.0.1-SNAPSHOT</version><name>gulimall-third-party</name><description>第三方服务</description><properties><java.version>1.8</java.version><spring-cloud.version>Greenwich.SR3</spring-cloud.version></properties><dependencies><dependency><groupId>com.atguigu.gulimall</groupId><artifactId>gulimall-common</artifactId><version>0.0.1-SNAPSHOT</version><exclusions><exclusion><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alicloud-oss</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.0.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url></repository></repositories>
</project>
  • ②. bootstrap.properties配置nacos配置中心
spring.application.name=gulimall-third-party
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=39e31ec7-194c-4741-b4f2-2b65142c2100
spring.cloud.nacos.config.ext-config[0].data-id=oss.yml
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[0].refresh=true
  • ③. application.yaml
spring:cloud:nacos:discovery:server-addr: 127.0.0.1:8848alicloud:access-key: LTAI5t7E9sokgukBNzP45nX1secret-key: yKzdbTeQETI4u9okOAPDvSscEa5pVToss:endpoint: oss-cn-guangzhou.aliyuncs.combucket: gulimall-tangzhiapplication:name: gulimall-third-party
server:port: 30000
  • ④. 网关的设置
spring:cloud:gateway:routes:- id: third_party_routeuri: lb://gulimall-third-partypredicates:- Path=/api/thirdparty/**filters:- RewritePath=/api/thirdparty/(?<segment>/?.*), /$\{segment}
  • ⑤. 对gulimall-third-party进行功能测试
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class GulimallThirdPartyApplicationTests {@AutowiredOSSClient ossClient;@Testpublic void uploadCloudAlibaba()throws Exception{// 填写本地文件的完整路径。如果未指定本地路径'则默认从示例程序所属项目对应本地路径中上传文件流。InputStream inputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\car2.jpg");// 依次填写Bucket名称(例如examplebucket)和Object完整路径(例如exampledir/exampleobject.txt)。Object完整路径中不能包含Bucket名称。ossClient.putObject("gulimall-tangzhi", "car3.jpg", inputStream);}
}

⑦. 服务端签名后直传

  • ①. 服务端签名后直传

  • ②. 背景
    采用JavaScript客户端直接签名(参见JavaScript客户端签名直传)时’AccessKey ID和AcessKey Secret会暴露在前端页面’因此存在严重的安全隐患。因此’OSS提供了服务端签名后直传的方案。

  • ③. 流程介绍

  • ④. 编写核心controller
    http://localhost:88/api/thirdparty/oss/policy

@RestController
public class OssController {@AutowiredOSS ossClient;@Value("${spring.cloud.alicloud.oss.endpoint}")private String endpoint;@Value("${spring.cloud.alicloud.oss.bucket}")private String bucket;@Value("${spring.cloud.alicloud.access-key}")private String accessId;@RequestMapping("/oss/policy")public R policy() {//https://gulimall-hello.oss-cn-beijing.aliyuncs.com/hahaha.jpgString host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint// callbackUrl为 上传回调服务器的URL'请将下面的IP和Port配置为您自己的真实信息。
//        String callbackUrl = "http://88.88.88.88:8888";String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());String dir = format + "/"; // 用户上传文件时指定的前缀。Map<String, String> respMap = null;try {long expireTime = 30;long expireEndTime = System.currentTimeMillis() + expireTime * 1000;Date expiration = new Date(expireEndTime);PolicyConditions policyConds = new PolicyConditions();policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);byte[] binaryData = postPolicy.getBytes("utf-8");String encodedPolicy = BinaryUtil.toBase64String(binaryData);String postSignature = ossClient.calculatePostSignature(postPolicy);respMap = new LinkedHashMap<String, String>();respMap.put("accessid", accessId);respMap.put("policy", encodedPolicy);respMap.put("signature", postSignature);respMap.put("dir", dir);respMap.put("host", host);respMap.put("expire", String.valueOf(expireEndTime / 1000));// respMap.put("expire", formatISO8601Date(expiration));} catch (Exception e) {// Assert.fail(e.getMessage());System.out.println(e.getMessage());}return R.ok().put("data",respMap);}
}

⑧. 结合前端实现文件直传

  • ①. 这里提供了三个js文件,直接导入项目即可
  1. policy.js封装一个Promise’发送/thirdparty/oss/policy请求。vue项目会自动加上api前缀
  2. multiUpload.vue多文件上传。要改’改方式如下
  3. singleUpload.vue单文件上传。要替换里面的action中的内容。
    action=“http://gulimall-tangzhi.oss-cn-guangzhou.aliyuncs.com”
<template> <div><el-uploadaction="http://gulimall-tangzhi.oss-cn-guangzhou.aliyuncs.com":data="dataObj"list-type="picture":multiple="false" :show-file-list="showFileList":file-list="fileList":before-upload="beforeUpload":on-remove="handleRemove":on-success="handleUploadSuccess":on-preview="handlePreview"><el-button size="small" type="primary">点击上传</el-button><div slot="tip" class="el-upload__tip">只能上传jpg/png文件'且不超过10MB</div></el-upload><el-dialog :visible.sync="dialogVisible"><img width="100%" :src="fileList[0].url" alt=""></el-dialog></div>
</template>
<script>import {policy} from './policy'import { getUUID } from '@/utils'export default {name: 'singleUpload',props: {value: String},computed: {imageUrl() {return this.value;},imageName() {if (this.value != null && this.value !== '') {return this.value.substr(this.value.lastIndexOf("/") + 1);} else {return null;}},fileList() {return [{name: this.imageName,url: this.imageUrl}]},showFileList: {get: function () {return this.value !== null && this.value !== ''&& this.value!==undefined;},set: function (newValue) {}}},data() {return {dataObj: {policy: '',signature: '',key: '',ossaccessKeyId: '',dir: '',host: '',// callback:'',},dialogVisible: false};},methods: {emitInput(val) {this.$emit('input', val)},handleRemove(file, fileList) {this.emitInput('');},handlePreview(file) {this.dialogVisible = true;},beforeUpload(file) {let _self = this;return new Promise((resolve, reject) => {policy().then(response => {_self.dataObj.policy = response.data.policy;_self.dataObj.signature = response.data.signature;_self.dataObj.ossaccessKeyId = response.data.accessid;_self.dataObj.key = response.data.dir +getUUID()+'_${filename}';_self.dataObj.dir = response.data.dir;_self.dataObj.host = response.data.host;resolve(true)}).catch(err => {reject(false)})})},handleUploadSuccess(res, file) {console.log("上传成功...")this.showFileList = true;this.fileList.pop();this.fileList.push({name: file.name, url: this.dataObj.host + '/' + this.dataObj.key.replace("${filename}",file.name) });this.emitInput(this.fileList[0].url);}}}
</script>
<style>
</style>
<template><div><el-uploadaction="http://gulimall-tangzhi.oss-cn-guangzhou.aliyuncs.com":data="dataObj"list-type="picture-card":file-list="fileList":before-upload="beforeUpload":on-remove="handleRemove":on-success="handleUploadSuccess":on-preview="handlePreview":limit="maxCount":on-exceed="handleExceed"><i class="el-icon-plus"></i></el-upload><el-dialog :visible.sync="dialogVisible"><img width="100%" :src="dialogImageUrl" alt /></el-dialog></div>
</template>
<script>
import { policy } from "./policy";
import { getUUID } from "@/utils";
export default {name: "multiUpload",props: {//图片属性数组value: Array,//最大上传图片数量maxCount: {type: Number,default: 30}},data() {return {dataObj: {policy: "",signature: "",key: "",ossaccessKeyId: "",dir: "",host: "",uuid: ""},dialogVisible: false,dialogImageUrl: null};},computed: {fileList() {let fileList = [];for (let i = 0; i < this.value.length; i++) {fileList.push({ url: this.value[i] });}return fileList;}},mounted() {},methods: {emitInput(fileList) {let value = [];for (let i = 0; i < fileList.length; i++) {value.push(fileList[i].url);}this.$emit("input", value);},handleRemove(file, fileList) {this.emitInput(fileList);},handlePreview(file) {this.dialogVisible = true;this.dialogImageUrl = file.url;},beforeUpload(file) {let _self = this;return new Promise((resolve, reject) => {policy().then(response => {console.log("这是什么${filename}");_self.dataObj.policy = response.data.policy;_self.dataObj.signature = response.data.signature;_self.dataObj.ossaccessKeyId = response.data.accessid;_self.dataObj.key =response.data.dir + "/" + getUUID() + "_${filename}";_self.dataObj.dir = response.data.dir;_self.dataObj.host = response.data.host;resolve(true);}).catch(err => {console.log("出错了...", err);reject(false);});});},handleUploadSuccess(res, file) {this.fileList.push({name: file.name,// url: this.dataObj.host + "/" + this.dataObj.dir + "/" + file.name; 替换${filename}为真正的文件名url:this.dataObj.host +"/" +this.dataObj.key.replace("${filename}", file.name)});this.emitInput(this.fileList);},handleExceed(files, fileList) {this.$message({message: "最多只能上传" + this.maxCount + "张图片",type: "warning",duration: 1000});}}
};
</script>
<style></style>
import http from '@/utils/httpRequest.js'
export function policy() {return  new Promise((resolve,reject)=>{http({url: http.adornUrl("/thirdparty/oss/policy"),method: "get",params: http.adornParams({})}).then(({ data }) => {resolve(data);})});
}
  • ②. 点击文件上传,出现了跨域,在oss官方文档有强调说明,一定要设置跨越

  • ③. 显示图片

<el-table-column prop="logo" header-align="center" align="center" label="品牌logo地址"><template slot-scope="scope"><!-- 自定义表格+自定义图片 --><img :src="scope.row.logo" style="width: 100px; height: 80px" /></template>
</el-table-column>

商城项目09_品牌管理菜单、快速显示开关、阿里云进行文件上传、结合Alibaba管理OSS、服务端签名后直传相关推荐

  1. 分布式电商项目二十六:使用阿里云存储的服务端签名后直传(前端联调)

    使用阿里云存储的服务端签名后直传(前端联调) 在前端显示上传的界面,可以根据人人fast-vue的结构,在src\components目录下添加upload文件夹,直接添加vue组件即可,总计三个组件 ...

  2. java百度云文件上传_关于如何在自己项目集成百度云BCE文件上传STS方案

    1. 项目背景 由于本人项目需要,需要在视频点播服务之中需要加载字幕文件(通用格式srt),经过比较好几家的公有云服务,最后选择只有百度云提供字幕服务. 字幕:我们通常在观看外语电影的是,没有国语版时 ...

  3. 阿里云视频点播-视频上传失败(一直显示上传中)

    控制台显示ErrorCode=null 这说明aliyun-java-vod-upload版本不对应 如今官网给出的最高版本为1.4.14,使用1.4.11版本即可上传成功 这里我将该1.4.11版本 ...

  4. ajax-FormData快速序列化表单数据以及文件上传

    serialize和 FormData 区别 $("form").serialize()和 new FormData($('#uploadForm')[0])都是序列化表单,实现表 ...

  5. 基于Django的文件上传下载删除管理器

    这是一个基于Django的文件下载,上传,删除的任务管理器 先看看效果展示 1.运行完Django后,直接输入网址http://127.0.0.1:8000 就可以直接进去该网站 2.这是一个主图 上 ...

  6. 网络编程学习(11)/ FTP项目(5) ——文件上传和上传断点续存功能

    网络编程学习(11)/ FTP项目(5) --文件上传和上传断点续存功能 `服务端 lib 文件夹下的 main.py 状态码的变化` 文件上传功能 `服务端 lib 文件夹下的 main.py` ` ...

  7. Silverlight多文件(大文件)上传的开源项目

    在Silverlight上实现文件上传的例子在网上的还不多,特别是多文件上传和大文件上传的例子就更少了.当然 那些商品软件公司的产品除外. 目前的CodePlex上就有这样一个项目,其链接:http: ...

  8. 推荐一个Silverlight多文件(大文件)上传的开源项目(转载)

    在Silverlight上实现文件上传的例子在网上的还不多,特别是多文件上传和大文件上传的例子就更少了.当然 那些商品软件公司的产品除外. 目前的CodePlex上就有这样一个项目,其链接:http: ...

  9. 在EasyUI项目中使用FileBox控件实现文件上传处理

    我在较早之前的随笔<基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用>Web框架介绍中介绍了基于Uploadify的文件上传操作,免费版本用的是J ...

最新文章

  1. OpenCV中使用SVM简介
  2. vector中erase函数
  3. DVD碟片输出与刻录简单流程
  4. 计算机操作系统还能这样玩?这一篇计算机操作系统的总结为你保驾护航(零风险、高质量、万字长文、建议收藏)
  5. SpringAop @AfterThrowing通知中获取异常信息并且在控制台打印
  6. HTML 中表单form 的相关知识
  7. Newbe.ObjectVisitor 0.4.4 发布,模型验证器上线
  8. js中执行到一个if就停止的代码_Node 中如何引入一个模块及其细节
  9. php替换文本域中的换行符,文本域中换行符的替换示例
  10. 设计模式原则(3)--Dependency Inversion Principle(DIP)--依赖倒转原则
  11. 重构Webpack系列之三 ----出口(output)
  12. cad统计面积长度插件vlx_cad计算面积插件免费版
  13. x240无线网卡驱动 linux,Linux2.6移植:DM9000驱动
  14. 游戏本地化翻译有哪些内容需要注意
  15. 价值 1500 美元的 iPhone 值得买吗
  16. 广度优先遍历搜索的最通俗介绍,如何实现广度优先搜索算法?广度优先遍历搜索可用于哪些行业?
  17. python3 学习之路1
  18. UT、IT、ST、UAT
  19. [vSphere]VCSA控制台修改root口令及关闭特定报警等操作
  20. mysql授权、关联查询、主外键关系

热门文章

  1. OpenLayers 3 之 添加地图网格
  2. C语言为什么不会过时?
  3. 用精密减压阀控制空气采样泵气体压力
  4. 软件开发过程大观——软件开发过程改进为什么能帮助软件质量提升?
  5. PyDraw 所见即所得的 Python GUI 绘制框架 开源代码源自 JY Lin
  6. 【CSS】笔记3-三大样式、盒子模型、PS、圆角、阴影
  7. Lync 2010移动客户端无法登陆的解决办法
  8. 电子设计教程12:Buck降压电路
  9. jess笔记_(2)
  10. 液晶拼接处理器_液晶拼接大屏运用设施