上一篇:微服务(三)—— MyBatis逆向工程模块(backend-generator).

目录

  • 一、创建项目
  • 二、项目结构
    • 1.目录结构
    • 2.pom.xml
    • 3.配置文件application.yml
    • 4.启动项目

一、创建项目

首先创建一个SpringBoot和Spring Cloud项目,这里需要考虑SpringBoot和Spring Cloud的版本问题

这是官网给的Spring Cloud对应的Spring Boot版本

在BackendManageSystem模块new 一个 module

选择Spring Initializr,点击Next
选择版本

选择Spring Boot版本,Idea里都是最新版,我使用的是2.2.2版本,创建后修改Maven依赖即可;Lombok用于加构造方法注解;
然后是Web,JDBC、Mybatis相关的依赖,因为用户系统是需要往注册中心注册的,注册中心使用的是Spring Cloud的Eureka组件,所以需要Eureka Discover Client依赖;

创建项目名称

二、项目结构

1.目录结构


controller用来接收前端的请求,下面看UserController的具体细节

package com.aiun.user.controller;
/*** 用户模块控制层* @author lenovo*/
@Api(tags = "用户系统相关接口")
@RestController
@RequestMapping("/user/")
public class UserController {@Autowiredprivate IUserService iUserService;@Autowiredprivate RedisTemplate<String, String> redisTemplate;/*** 用户登录* @param username 用户名* @param password 密码* @return 返回登录信息*/@PostMapping("login")@ApiOperation(value = "用户登录", notes = "用户登录")public ServerResponse<User> login(String username, String password) {ServerResponse<User> response = iUserService.login(username, password);return response;}/*** 用户注册* @param user 用户信息* @return 返回注册信息*/@PostMapping("register")@ApiOperation(value = "用户注册")public ServerResponse<String> register(User user) {return iUserService.register(user);}/*** 退出登录* @param request 请求* @return 返回退出状态*/@PostMapping("logout")@ApiOperation(value = "用户登录退出")public ServerResponse<String> logout(HttpServletRequest request) {String key = request.getHeader(UserConst.AUTHORITY);ValueOperations<String, String> operations = redisTemplate.opsForValue();String value = operations.get(key);User user = JsonUtils.jsonStr2Object(value, User.class);if (key.equals(user.getUsername())) {redisTemplate.delete(key);return ServerResponse.createBySuccessMessage("退出成功");}return ServerResponse.createBySuccessMessage("当前用户未登录");}/*** 验证信息* @param str 校验的数据* @param type 类型(userName, email)* @return 返回校验结果*/@PostMapping("check_valid")@ApiOperation(value = "验证信息")public ServerResponse<String> checkValid(String str, String type){return iUserService.checkValid(str, type);}/*** 获取用户信息* @param request 请求* @return 返回用户信息*/@PostMapping("get_information")@ApiOperation(value = "获取用户信息")public ServerResponse<User> getInformation(HttpServletRequest request) {ServerResponse hasLogin = loginHasExpired(request);if (hasLogin.isSuccess()) {User user = (User) hasLogin.getData();return iUserService.getInformation(user.getId());}return hasLogin;}/*** 判断用户登录是否过期*/private ServerResponse<User> loginHasExpired(HttpServletRequest request) {String key = request.getHeader(UserConst.AUTHORITY);ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();String value = valueOperations.get(key);if (StringUtils.isEmpty(value)) {return ServerResponse.createByErrorMessage(ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());}User user = JsonUtils.jsonStr2Object(value, User.class);if (!key.equals(user.getUsername())) {return ServerResponse.createByErrorMessage(ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());}valueOperations.set(key, value, 1, TimeUnit.HOURS);return ServerResponse.createBySuccess(user);}
}

这里涉及到接口文档描述Swagger和微服务单点登录问题,看后面介绍。
微服务(十二)—— Swagger.
微服务(十)—— 单点登录.
controller层调用service层接口,下面看service层的实现类UserServiceImpl

package com.aiun.user.service.impl;/*** 用户模块实现类* @author lenovo*/
@Service("iUserService")
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate RedisTemplate<String,String> redisTemplate;@Overridepublic ServerResponse<User> login(String userName, String password) {int resultCount = userMapper.checkUsername(userName);if (resultCount <= 0) {return ServerResponse.createByErrorMessage("用户名不存在");}//密码登录并MD5加密String md5password = MD5Utils.MD5EncodeUtf8(password);User user = userMapper.selectLogin(userName, md5password);if (user == null) {return ServerResponse.createByErrorMessage("密码错误");}String key = userName;String token = JsonUtils.object2JsonStr(user);ValueOperations<String, String>valueOperations = redisTemplate.opsForValue();//用户登录成功后,将该用户对象作为token值保存到redis里,并且设置过期时间为1小时valueOperations.set(key, token, 1, TimeUnit.HOURS);return ServerResponse.createBySuccess("登录成功", user);}@Overridepublic ServerResponse<String> register(User user) {ServerResponse validResponse = this.checkValid(user.getUsername(), UserConst.USERNAME);if (!validResponse.isSuccess()) {return validResponse;}validResponse = this.checkValid(user.getEmail(), UserConst.EMAIL);if (!validResponse.isSuccess()) {return validResponse;}// 指定用户角色user.setRole(UserConst.Role.ROLE_CUSTOMER);// MD5 加密user.setPassword(MD5Utils.MD5EncodeUtf8(user.getPassword()));int resultCount = userMapper.insert(user);if(resultCount == 0) {return ServerResponse.createByErrorMessage("注册失败");}return ServerResponse.createBySuccessMessage("注册成功");}@Overridepublic ServerResponse<User> getInformation(int userId) {User user = userMapper.selectByPrimaryKey(userId);if(user == null) {return ServerResponse.createByErrorMessage("当前用户不存在");}user.setPassword(StringUtils.EMPTY);return ServerResponse.createBySuccess(user);}//.......
}

用户接口层IUserService

package com.aiun.user.service;/*** 用户接口* @author lenovo*/
public interface IUserService {/*** 用户登录* @param userName* @param password* @return*/ServerResponse<User> login(String userName, String password);/*** 注册* @param user* @return*/ServerResponse<String> register(User user);/*** 用户名或邮箱的校验* @param str* @param type* @return*/ServerResponse<String> checkValid(String str, String type);/*** 获取用户信息* @param userId* @return*/ServerResponse<User> getInformation(int userId);/*** 更改密码* @param oldPassword* @param newPassword* @param user* @return*/ServerResponse<String> resetPassword(String oldPassword, String newPassword, User user);
}

Server层的实现类调用DAO层的Mapper层,UserMapper如下:

package com.aiun.user.mapper;@Mapper
@Repository
public interface UserMapper {/*** 根据主键删除用户* @param id 主键* @return 影响的记录行数*/int deleteByPrimaryKey(Integer id);/*** 插入用户* @param record 用户信息* @return 影响的记录行数*/int insert(@Param("record") User record);/*** 有选择的插入用户* @param record 用户信息* @return 影响的记录行数*/int insertSelective(@Param("record") User record);/*** 通过主键查询用户* @param id 主键* @return 用户信息*/User selectByPrimaryKey(Integer id);/*** 通过主键有选择的更新用户* @param record 用户信息* @return 影响的记录行数*/int updateByPrimaryKeySelective(@Param("record") User record);/*** 通过主键更新用户* @param record 用户信息* @return 影响的记录行数*/int updateByPrimaryKey(@Param("record") User record);/*** 登录* @param username 用户名* @param password 密码* @return 返回用户信息*/User selectLogin(@Param("username") String username, @Param("password") String password);/*** 检查用户名* @param username 用户名* @return 影响的记录行数*/int checkUsername(String username);/*** 检查email* @param email 邮箱* @return 影响的记录行数*/int checkEmail(String email);/*** 检查密码* @param password* @param userId* @return*/int checkPassword(@Param("password") String password, @Param("userId") Integer userId);
}

注:这个Mapper层的接口除了要写Spring的@Repository注解,还需要写@Mapper注解,这个注解是告诉SpringBoot这是DAO层的Mapper映射接口,与这个接口对应的是mapper.xml文件,注意是SQL语句的编写,如下UserMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.aiun.user.mapper.UserMapper" ><resultMap id="BaseResultMap" type="com.aiun.user.pojo.User" ><constructor ><idArg column="id" jdbcType="INTEGER" javaType="java.lang.Integer" /><arg column="username" jdbcType="VARCHAR" javaType="java.lang.String" /><arg column="password" jdbcType="VARCHAR" javaType="java.lang.String" /><arg column="email" jdbcType="VARCHAR" javaType="java.lang.String" /><arg column="phone" jdbcType="VARCHAR" javaType="java.lang.String" /><arg column="question" jdbcType="VARCHAR" javaType="java.lang.String" /><arg column="answer" jdbcType="VARCHAR" javaType="java.lang.String" /><arg column="role" jdbcType="INTEGER" javaType="java.lang.Integer" /><arg column="create_time" jdbcType="TIMESTAMP" javaType="java.util.Date" /><arg column="update_time" jdbcType="TIMESTAMP" javaType="java.util.Date" /></constructor></resultMap><sql id="Base_Column_List" >id, username, password, email, phone, question, answer, role, create_time, update_time</sql><select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >select<include refid="Base_Column_List" />from trade_userwhere id = #{id,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >delete from trade_userwhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="com.aiun.user.pojo.User" >insert into trade_user (id, username, password,email, phone, question,answer, role, create_time,update_time)values (#{record.id,jdbcType=INTEGER}, #{record.username,jdbcType=VARCHAR}, #{record.password,jdbcType=VARCHAR},#{record.email,jdbcType=VARCHAR}, #{record.phone,jdbcType=VARCHAR}, #{record.question,jdbcType=VARCHAR},#{record.answer,jdbcType=VARCHAR}, #{record.role,jdbcType=INTEGER}, now(),now())</insert><insert id="insertSelective" parameterType="com.aiun.user.pojo.User" >insert into trade_user<trim prefix="(" suffix=")" suffixOverrides="," ><if test="id != null" >id,</if><if test="username != null" >username,</if><if test="password != null" >password,</if><if test="email != null" >email,</if><if test="phone != null" >phone,</if><if test="question != null" >question,</if><if test="answer != null" >answer,</if><if test="role != null" >role,</if><if test="createTime != null" >create_time,</if><if test="updateTime != null" >update_time,</if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="id != null" >#{record.id,jdbcType=INTEGER},</if><if test="username != null" >#{record.username,jdbcType=VARCHAR},</if><if test="password != null" >#{record.password,jdbcType=VARCHAR},</if><if test="email != null" >#{record.email,jdbcType=VARCHAR},</if><if test="phone != null" >#{record.phone,jdbcType=VARCHAR},</if><if test="question != null" >#{record.question,jdbcType=VARCHAR},</if><if test="answer != null" >#{record.answer,jdbcType=VARCHAR},</if><if test="role != null" >#{record.role,jdbcType=INTEGER},</if><if test="createTime != null" >#{record.createTime,jdbcType=TIMESTAMP},</if><if test="updateTime != null" >now(),</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="com.aiun.user.pojo.User" >update trade_user<set ><if test="record.username != null" >username = #{record.username,jdbcType=VARCHAR},</if><if test="record.password != null" >password = #{record.password,jdbcType=VARCHAR},</if><if test="record.email != null" >email = #{record.email,jdbcType=VARCHAR},</if><if test="record.phone != null" >phone = #{record.phone,jdbcType=VARCHAR},</if><if test="record.question != null" >question = #{record.question,jdbcType=VARCHAR},</if><if test="record.answer != null" >answer = #{record.answer,jdbcType=VARCHAR},</if><if test="record.role != null" >role = #{record.role,jdbcType=INTEGER},</if><if test="record.createTime != null" >create_time = #{record.createTime,jdbcType=TIMESTAMP},</if><if test="record.updateTime != null" >update_time = now(),</if></set>where id = #{record.id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="com.aiun.user.pojo.User" >update trade_userset username = #{record.username,jdbcType=VARCHAR},password = #{record.password,jdbcType=VARCHAR},email = #{record.email,jdbcType=VARCHAR},phone = #{record.phone,jdbcType=VARCHAR},question = #{record.question,jdbcType=VARCHAR},answer = #{record.answer,jdbcType=VARCHAR},role = #{record.role,jdbcType=INTEGER},create_time = #{record.createTime,jdbcType=TIMESTAMP},update_time = now()where id = #{id,jdbcType=INTEGER}</update><select id="checkUsername" resultType="int" parameterType="string">select count(1) from trade_userwhere username = #{username}</select><select id="selectLogin" resultMap="BaseResultMap" parameterType="map">select<include refid="Base_Column_List" />from trade_userwhere username = #{username}and password = #{password}</select><select id="checkEmail" resultType="int" parameterType="string">select count(1) from trade_userwhere email = #{email}</select><select id="checkPassword" resultType="int" parameterType="map">select count(1) from trade_userwhere id = #{userId}and password = #{password}</select>
</mapper>

对于返回User对象的我用BaseResultMap进行映射和封装。
数据库建表语句:

CREATE TABLE reade_user (id int(11) NOT NULL AUTO_INCREMENT COMMENT ‘用户表id’,username varchar(50) NOT NULL COMMENT ‘用户名’,password varchar(50) NOT NULL COMMENT ‘用户密码,MD5加密’,email varchar(50) DEFAULT NULL,phone varchar(20) DEFAULT NULL,question varchar(100) DEFAULT NULL COMMENT ‘找回密码问题’,answer varchar(100) DEFAULT NULL COMMENT ‘找回密码答案’,role int(4) NOT NULL COMMENT ‘角色0-管理员,1-普通用户’,create_time datetime NOT NULL COMMENT ‘创建时间’,update_time datetime NOT NULL COMMENT ‘最后一次更新时间’,PRIMARY KEY (id),UNIQUE KEY user_name_unique (username) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;

2.pom.xml

首先引入父模块依赖

<parent><groupId>com.aiun</groupId><artifactId>BackendManageSystem</artifactId><version>1.0-SNAPSHOT</version>
</parent>

引入backend common 依赖

<dependency><groupId>com.aiun</groupId><artifactId>backend-common</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

由于我在父模块添加了Spring Cloud依赖,所以这里就不需要添加Spring Cloud依赖,父模块的pom.xml文件见微服务(一)—— 项目结构.
pom.xml文件

<?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>com.aiun</groupId><artifactId>BackendManageSystem</artifactId><version>1.0-SNAPSHOT</version></parent><groupId>com.aiun</groupId><artifactId>backend-user</artifactId><version>0.0.1-SNAPSHOT</version><name>backend-user</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><!--backend common 依赖--><dependency><groupId>com.aiun</groupId><artifactId>backend-common</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--config client 依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-client</artifactId></dependency><!--spring boot test 依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--spring boot web 依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mybatis 依赖--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!--mysql 依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--druid 连接池依赖--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId></dependency><!-- lombok 依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- swagger 依赖--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><repositories><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories>
</project>

3.配置文件application.yml

# Spring
spring:# 服务应用名称application:name: backend-user# 数据源datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/trade?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: rootpassword: root# 指定druid 连接池以及druid 连接池配置type: com.alibaba.druid.pool.DruidDataSourcedruid:initial-size: 1          # 初始连接数max-active: 20           # 最大连接数max-idle: 20             # 最大空闲min-idle: 1              # 最小空闲max-wait: 60000          # 最长等待时间server:port: 8084                  # 项目访问端口servlet:context-path: /backend-user  # 项目访问路径eureka:client:service-url:defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/instance:hostname: localhost# MyBatis
mybatis:# 配置 MyBatis 数据返回类型别名(默认别名是类名)type-aliases-package: com.aiun.user.pojo# 配置 MyBatis Mapper 映射文件mapper-locations: classpath:/mappers/*.xml# MyBatis SQL 打印(方法接口所在的包,不是 Mapper.xml 所在的包)
# logging:# level:# com.aiun.order.mappers: debug# pagehelperpagehelper:helperDialect: sqlite #postgresqlreasonable: truesupportMethodsArguments: trueparams: countSqlcount: countSqlreturnPageInfo: check# 记录日志logging:config: classpath:logback-spring.xml

该文件是SpringBoot的配置文件,与properties文件不同的是它是键: 值,并且冒号后面要有一个空格,包的子目录也是通过空格体现,而且一个文件可以配置几个模块,例如上面我配置了开发环境dev和测试环境test,通过—符号进行分割。
这个配置文件主要配置的是应用名称、访问路径、端口、数据库、数据库连接池、日志和其他框架的配置。

4.启动项目

打开SpringBoot的启动类UserApplication

package com.aiun.user;/*** 用户模块启动类* @author lenovo*/
@SpringBootApplication
public class UserApplication {public static void main(String[] args) {SpringApplication.run(UserApplication.class, args);}
}

启动该项目即可,然后就可以通过访问http://localhost:8084/backend-user/user/访问项目了
我这里通过Google插件Talend API Test进行后端接口测试

成功!!!
到这里用户模块就完成了。
注:项目已上传GitHub:https://github.com/AiunCode/BackendManageSystem.

下一篇:微服务(五)—— 产品模块(backend-product).

微服务(四)—— 用户模块(backend-user)相关推荐

  1. 微服务间用户信息共享机制

    文章目录 前言 第一节 微服务间用户信息传递问题 第二节 解决思路 第三节 实践操作(基于Feign) 1. 调用链路说明 2. shop-common改造 3. 开启注解 4. 启动服务器测试 第四 ...

  2. ASP.NET Core微服务(四)——【静态vue使用axios解析接口】

    ASP.NET Core微服务(二)--[ASP.NET Core Swagger配置]: 环境:win10专业版+vs2019+sqlserver2014/2019+vsCode+在线资源 boot ...

  3. JWT(解决前后端分离和微服务的用户会话跟踪问题)

    这里写目录标题 JWT:解决前后端分离和微服务的用户会话跟踪问题 与传统sessio验证的区别: 基于 token 的鉴权机制 JWT的主要引用场景及优点 JWT的构成: JWT搭建 案例: JWT: ...

  4. 微服务项目-订单模块

    准备工作 参照之前的文章搭建好项目架构,接下来开始写订单模块的后端接口.接口文档在开源仓库上有,仓库地址在第一篇博客上有. 新建订单服务模块 1.创建新模块 模块继承主工程依赖依赖 2.导入相关依赖 ...

  5. 从单机应用到微服务,用户认证走几步?

    用户认证指在用户访问服务的时候确认用户的身份,受限于HTTP无状态的特性,应用开发者需要自行实现用户认证相关功能. 通常是用户登录时服务端生成通行证返回给客户端,客户端在接下来的请求中携带通行证,然后 ...

  6. 微服务四个常见问题,以及SpringCloud Netflix和SpringCloud Alibaba和Apache Dubbo zookeeper区别

    微服务的四个问题 1.服务很多,客户端该怎么访问? 2.这么多服务? 服务之间如何通信? 3.这么多服务? 如何治理? 4.服务挂了怎么办? 提出三种解决方案 1.spring cloud NetFl ...

  7. go-kratos 微服务框架 warden模块使用

    pb文件 创建项目成功后,进入api目录下可以看到api.proto文件: option go_package = "api"; option (gogoproto.goproto ...

  8. 陌陌 php微服务架构,微服务架构中模块划分和服务识别

    沙龙晃荡 | 去哪儿.陌陌.ThoughtWorks在主动化运维中的实践!10.28不见不散! 比来在进行微办事架构的交换和评论辩论中,除了谈到微办事迹巧架构外,客户往往加倍挂你微办事模块的划分粒度, ...

  9. SpringCloud(第 002 篇)简单电影微服务类(消费方,而提供方为用户微服务)

    2019独角兽企业重金招聘Python工程师标准>>> SpringCloud(第 002 篇)简单电影微服务类(消费方,而提供方为用户微服务) 一.大致介绍 微服务与微服务之间通过 ...

  10. spring cloud、gradle、父子项目、微服务框架搭建---搭建父子级多模块项目,并注册到Eureka注册中心(二)

    总目录 https://preparedata.blog.csdn.net/article/details/120062997 一.新建一个父级gradl模块 1.在桌面或新建文件里面,右键,打开ID ...

最新文章

  1. 《一个操作系统的实现》——pmtest1.asm详解
  2. mongodb数据库扩展名_MongoDB学习笔记:MongoDB 数据库的命名、设计规范
  3. “error LNK2019: 无法解析的外部符号”的几种可能原因
  4. 使用行动列表去创造简单且可扩展的游戏AI
  5. 【Linux】一步一步学Linux——dpkg命令(269)
  6. Java笔记-spring-rabbitmq中使用@RabbitListener消费(手动确认,获header数据)
  7. 开放防火墙/26ip段_在5个不同国家/地区采用开放硬件设计的电子产品
  8. java logic逻辑,logicJava的复习
  9. python达内教程_达内教你如何零基础入门python编程
  10. Just do IT --- gulp
  11. TIOBE 3 月编程语言排行榜出炉:Roblox 带飞 Lua,重回 TOP 20!
  12. macos 运行linux,MacOS 上运行shell
  13. 高手对中科院考博英语的分享
  14. Javashop连锁门店系统帮助企业快速搭建自己企业商城
  15. 产品 电信nb接口调用_【IoT】物联网NB-IoT之电信物联网开放平台对接流程浅析
  16. EZchip花1.3亿美元买Tilera然后以8亿美元把自己与Tilera一起卖掉
  17. 绘声绘影X4 个人MV制作
  18. 高通开发系列 - 总目录
  19. 关于 ONLYOFFICE 的安卓 Android 手机版
  20. 教师资格证报名浏览器不兼容 - 解决方案

热门文章

  1. 使用Airline自定义command (Java)
  2. 前端架构设计第一课 CI环境npm/Yarn
  3. 微信自动回复群聊机器人
  4. 我为什么不再推荐RxJava
  5. linux moxa 多串口卡_在FC6 Linux下安装Moxa多串口卡的问题
  6. 5.2 缺失值处理(去除缺失值)
  7. pkg文件--一种简单的游戏资源打包格式
  8. 数字媒体技术专业与影视特效的发展和联系
  9. 计算机族的健康饮品,健康生活习惯,护眼诀窍---多 活 十 年
  10. 中国分离机械产业“十四五”投资规划及发展潜力研究报告2022~2028年