SpringBoot项目--电脑商城【用户注册】

news2024/11/27 9:56:56

1.创建数据表

1.1 创建t_user表

CREATE TABLE t_user (
	uid INT AUTO_INCREMENT COMMENT '用户id',
	username VARCHAR(20) NOT NULL UNIQUE COMMENT '用户名',
	`password` CHAR(32) NOT NULL COMMENT '密码',
	salt CHAR(36) COMMENT '盐值',
	phone VARCHAR(20) COMMENT '电话号码',
	email VARCHAR(30) COMMENT '电子邮箱',
	gender INT COMMENT '性别:0-女,1-男',
	avatar VARCHAR(50) COMMENT '头像',
	is_delete INT COMMENT '是否删除:0-未删除,1-已删除',
	created_user VARCHAR(20) COMMENT '日志-创建人',
	created_time DATETIME COMMENT '日志-创建时间',
	modified_user VARCHAR(20) COMMENT '日志-最后修改执行人',
	modified_time DATETIME COMMENT '日志-最后修改时间',
	PRIMARY KEY (uid)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

1. 2 创建用户的实体类

将来任何一张表都有以下四个字段:

created_user VARCHAR(20) COMMENT ‘创建人’,

created_time DATETIME COMMENT ‘创建时间’,

modified_user VARCHAR(20) COMMENT ‘修改人’,

modified_time DATETIME COMMENT ‘修改时间’,

所以为了开发方便可以把这四个字段作为整个实体类

1.通过表的结构提取出表的公共字段,放在一个实体类的基类中,起名BaseEntity基类中

/**
 * 实体类的基类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseEntity implements Serializable {
    private String createdUser;
    private Date createdTime;
    private String modifiedUser;
    private Date modifiedTime;
}

2.创建用户的实体类,并使其继承BaseEntity基类

/**
 * 用户实体类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User extends BaseEntity implements Serializable {
    private Integer uid;//用户id
    private String username;//用户名
    private String password;//密码
    private String salt;//盐值
    private String phone;//电话号码
    private String email;//电子邮箱
    private Integer gender;//性别:0-女,1-男
    private String avatar;//头像
    private Integer isDelete;//是否删除:0-未删除,1-已删除
}

注意点:

  • 实体类User因为要在网络中以流的形式传输,所以需要serialize序列化(但因为其继承的父类BaseEntity已经实现序列化,所以就不需要再写implements Serializable)

  • ssm框架开发项目的时候需要在实体类上面加@Component然后spring才能自动进行对象的创建维护,而springboot不再需要,因为springboot遵循的原则是约定大于配置,如果字段名称相同那就可以自动完成字段的初始化

2.  持久层[Mapper]

a. 规划需要执行的SQL语句

1.用户的注册功能,从后端持久层来看相当于在做数据的插入操作

inser into t_user (username)

2.在用户的注册时首先要去查询当前的用户名是否存在,如果存在则不能进行注册,相当于是一条查询语句

select * from t_user where username=?

b.设计接口和抽象方法及实现

1.定义Mapper接口.在项目的目录结构下首先创建一个mapper包,在这个包下再根据不同的功能模块来创建mapper接口.注册功能需要在mapper包下创建UserMapper接口然后定义上述两个SQL语句的抽象方法

/**
 * 用户模块的持久层接口
 */
//@Mapper
public interface UserMapper {

    /**
     * 插入用户的数据
     *
     * @param user
     * @return:受到影响的行数
     */
    Integer insert(User user);

    /**
     * 根据用户名来查询用户数据
     * @param username
     * @return:如果找到对应的用户则返回这个用户的数据,如果没有则返回null
     */
    User findByUsername(String username);
}

2.ssm框架开发项目的时候需要在mapper接口上加@Mapper用于自动生成相应的接口实现类,在springboot也可以这样,但是后续会有很多mapper接口,每个接口分别加@Mapper太麻烦了,所以在启动类类里面指定当前项目的mapper接口在哪,然后项目启动的时候会自动加载所有的接口

//MapperScan注解指定当前项目中Mapper接口路径的位置,在项目启动的时候自动加载所有的接口
@MapperScan("com.example.mycomputerstore.mapper")

c. 编写映射


1.定义xml映射文件,与对应的接口进行关联.所有的映射文件都属于资源文件,需要放在resources目录下,为了管理方便我们在resources目录下创建一个mapper文件夹,然后在这个文件夹里存放mapper的映射文件

2.创建接口的映射文件,需要和接口的名称保持一致.如UserMapper.xml

UserMapper.xml的配置在Mybatis官网

<?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">
<!--namespace用于指定当前的映射文件和哪个接口进行映射,需要指定接口的文件路径,路径需要是包的完整路径结构-->
<mapper namespace="com.example.mycomputerstore.mapper.UserMapper">

</mapper>

3.将配置接口的方法对应到SQL语句上

insert into () values (),因为values后面插入的值是动态值,mybatis规定需要用占位符来占位,并给占位符起一个变量的名字,且变量的名字需要在占位符#{}内部
创建t_user表时uid INT AUTO_INCREMENT COMMENT ‘用户id’,中的AUTO_INCREMENT表示主键uid自增,所以需要useGeneratedKeys和keyProperty

    <!--自定义映射规则:resultMap标签来完成映射规则定义-->
    <!--id属性:标签给这个映射负责分配一个唯一的id值,对应的就是resultMap="id属性的值"属性的取值
        type属性:取值是一个类,表示的是数据库中的查询结果与Java中哪个实体类进行结果集的映射-->
    <resultMap id="UserEntityMap" type="com.example.mycomputerstore.entity.User">
        <!--将表的字段和类的属性不一致的字段进行匹配指定,名称一致的字段可以省略不写-->
        <!--
        配合完成名称不一致的映射:
        column属性:表示表中的资源名称
        property属性:表示类中的属性名称
        -->
        <!--在定义映射规则时主键是不可以省略的-->
        <id column="uid" property="uid"></id>
        <result column="is_delete" property="isDelete"></result>
        <result column="created_User" property="createdUser"></result>
        <result column="created_time" property="createdTime"></result>
        <result column="modified_user" property="modifiedUser"></result>
        <result column="modified_time" property="modifiedTime"></result>
    </resultMap>



    <!--id  表示映射的接口中方法的名称,直接在标签的内部来编写SQl语句

    过程:insert语句通过映射的接口做到和UserMapper内部方法对应
    useGeneratedKeys开启字段递增【主键】   keyProperty递增主键-->

    <insert id="insert" useGeneratedKeys="true" keyProperty="uid">
        INSERT INTO t_user (
            username,password,salt,phone,email,gender,avatar,is_delete,
            created_user,created_time,modified_user,modified_time
        ) VALUES (
                     /*动态值,需要用占位符进行占位,需要给每个占位符起个专门的名字*/
                     #{username},#{password},#{salt},#{phone},#{email},#{gender},#{avatar},#{isDelete},
                     #{createdUser},#{createdTime},#{modifiedUser},#{modifiedTime}
                 )
    </insert>

4.将mapper文件的位置注册到properties对应的配置文件中.

在application.properties文件中增添:

mybatis.mapper-locations=classpath:mapper/*.xml

d. 单元测试

每个独立的层编写完毕后需要编写单元测试方法来测试当前的功能:在test包结构下创建一个mapper包,在这个包下再创建持久层的功能测试,单元测试方法是独立运行,不用启动整个项目,提高了代码的测试效率

@SpringBootTest//表示标注当前的类是一个测试类,不会随同一块打包
//RunWith:表示启动这个单元测试类,需要传递一个参数,必须是SpringBoot的实例对象
@RunWith(SpringRunner.class)
public class UserMapperTests {

    //idea检测功能,接口是不能直接创建Bean(动态代理来解决)
    @Autowired
    private UserMapper userMapper;

    /**
     * 单元测试
     * 1.返回值必须是void
     * 2.必须是public
     */
    @Test
    public void insert(){
        User user = new User();
        user.setUsername("tim");
        user.setPassword("123");
        Integer rows = userMapper.insert(user);
        System.out.println(rows);
    }
    
    @Test
    public void findByUsername() {
        User user = userMapper.findByUsername("张三");
        System.out.println(user);
    }
}

3. 业务层[Service]

a. 业务层的核心功能:

  • 接受前端从控制器流转过来的数据
  • 结合真实的注册业务来完成功能业务逻辑的调转和流程

所以这里要考虑到真实的业务场景,如果只考虑业务场景的话不完整,因为在整个业务执行的过程中会产生很多问题,从java角度来讲这些都是属于异常,所以在业务开发的时候就要规划相关的异常,以便把项目的错误控制在一定范围内

b. service下的目录结构:

service包下创建ex包用来写异常类
service包下创建impl包用来写接口的实现类
接口直接写在service包下,不再需要接口包

c. 规划异常

1.为什么会有异常:

比如,用户在进行注册时可能会产生用户名被占用的错误,这时需要抛出一个异常

2.怎么处理异常:

异常不能用RuntimeException,太笼统了,开发者没办法第一时间定位到具体的错误类型上,我们可以定义具体的异常类型来继承这个异常.
正常的开发中异常又要分等级,可能是在业务层产生异常,可能是在控制层产生异常,所以可以创建一个业务层异常的基类,起名ServiceException异常,并使其继承RuntimeException异常
后期开发业务层时具体的异常可以再继承业务层的异常ServiceException


3.处理异常的具体步骤:

步骤一:在ex包下创建ServiceException类作为业务层异常的基类:


/**
 * 因为整个业务的异常只有一种情况下才会产生:只有运行时才会产生,不运行不会产生
 * 业务异常的基类:throw new ServiceException("业务层产生未知的异常")
 */
public class ServiceException extends RuntimeException{
    public ServiceException() {
        super();
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(Throwable cause) {
        super(cause);
    }

    protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

步骤二:后期再根据业务层不同的功能来详细定义具体的异常类型,并统一的继承ServiceException异常基类:

  • 用户在进行注册时可能会产生用户名被占用的错误,这时需要抛出一个UsernameDuplicatedException异常
/**
 * 用户名被占用的异常
 */
public class UsernameDuplicatedException extends ServiceException {
    //alt+insert---生成override methods

    public UsernameDuplicatedException() {
        super();
    }

    public UsernameDuplicatedException(String message) {
        super(message);
    }

    public UsernameDuplicatedException(String message, Throwable cause) {
        super(message, cause);
    }

    public UsernameDuplicatedException(Throwable cause) {
        super(cause);
    }

    protected UsernameDuplicatedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
  • 正在执行数据插入操作的时候,服务器宕机或数据库宕机.这种情况是处于正在执行插入的过程中所产生的异常,起名InsertException异常
/**
 * 数据在插入的异常
 */
public class InsertException extends ServiceException {
    public InsertException() {
        super();
    }

    public InsertException(String message) {
        super(message);
    }

    public InsertException(String message, Throwable cause) {
        super(message, cause);
    }

    public InsertException(Throwable cause) {
        super(cause);
    }

    protected InsertException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

d. 设计接口和抽象方法

1.在service包下创建IUserService接口(接口命名的默认规则:I+业务名字+层的名字)

/**用户模块业务层接口*/
public interface IUserService {
    /**
     * 用户注册方法
     * @param user 用户的数据对象
     */
    void reg(User user);
}

2.创建一个实现UserServiceImpl类,需要实现IUserService接口,并且实现抽象的方法

因为要将这个实现类交给spring管理,所以需要在类上加@Service

/**
 * 用户模块业务层实现类
 */
@Service//将当前类的对象交给Spring来管理,自动创建对象以及对象的维护
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void reg(User user) {
        //通过user参数来获取传递过来的username
        String username = user.getUsername();
        //调用findByUsername(username) 判断用户是否被注册过
        User result = userMapper.findByUsername(username);
        //判断结果集是否为null
        if(result!=null){
            //如果不为null则抛出用户名被占用的异常
            throw new UsernameDuplicatedException("用户名被占用");
        }

        //密码加密处理的实现:md5算法的形式:57hwdowhdow
        //串【盐值】+passsword+串【盐值】----md5算法进行加密,连续加载三次
        //盐值:随机的字符串
        String oldpassword = user.getPassword();
        //获取盐值(随机生成一个盐值)
        String salt = UUID.randomUUID().toString().toUpperCase();
        //补全数据:盐值的记录
        user.setSalt(salt);
        //将密码和盐值作为一个整体进行加密处理,忽略原有密码强度提升了数据安全性
        String md5Password = getMD5Password(oldpassword, salt);
        //将加密后的密码重新补全设置到user中
        user.setPassword(md5Password);

        //补全数据:is_delete设置为0
        user.setIsDelete(0);
        //补全数据:4个日志字段信息
        user.setCreatedUser(user.getUsername());
        user.setModifiedUser(user.getUsername());
        Date date = new Date();
        user.setCreatedTime(date);
        user.setModifiedTime(date);

        //执行注册业务功能的实现
        Integer rows = userMapper.insert(user);
        //执行插入成功rows=1
        if(rows!=1){
            throw new InsertException("用户注册过程产生了未知的异常");
        }
    }
}

md5加密算法以后可能还要多次用到,为了方便在UserServiceImpl类里面单独写一个getMD5Password方法

    /**
     * 定义一个md5算法的加密处理
     */
    private String getMD5Password(String password, String salt) {
        //MD5加密算法的调用(进行三次加密)
        for(int i=0;i<3;i++){
            password=DigestUtils.md5DigestAsHex((salt+password+salt).getBytes()).toUpperCase();
        }
        //返回之后的密码
        return password;
    }

e.单元测试

@SpringBootTest//表示标注当前的类是一个测试类,不会随同一块打包
//RunWith:表示启动这个单元测试类,需要传递一个参数,必须是SpringBoot的实例对象
@RunWith(SpringRunner.class)
public class UserServiceTests {


    //idea检测功能,接口是不能直接创建Bean(动态代理来解决)
    @Autowired
    private IUserService userService;

    /**
     * 单元测试
     * 1.返回值必须是void
     * 2.必须是public
     */
    @Test
    public void insert(){
        try {
            User user = new User();
            user.setUsername("smy");
            user.setPassword("123");
            userService.reg(user);
            System.out.println("ok");
        } catch (SecurityException e){
            //获取类的对象,在获取类的名称
            System.out.println(e.getClass().getSimpleName());
            //获取异常的具体描述信息
            System.out.println(e.getMessage());
        }
    }
}

4.控制层[controller]

4.1 创建响应

状态码,状态描述信息,数据是所有控制层对应的方法都涉及到的操作,所以把这部分功能封装到一个类JsonResult中,将这个类作为方法的返回值返回给前端浏览器:

/**
 * Json格式的数据进行响应
 */
@Data
public class JsonResult<E> implements Serializable {

    /**
     * 状态码
     */
    private Integer state;
    /**
     * 描述信息
     */
    private String message;
    /**
     * 数据
     */
    private E data;

    public JsonResult() {
    }

    public JsonResult(Integer state) {
        this.state = state;
    }

    public JsonResult(Throwable e) {
        this.message = e.getMessage();
    }

    public JsonResult(Integer state, E data) {
        this.state = state;
        this.data = data;
    }

    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        this.state = state;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public E getData() {
        return data;
    }

    public void setData(E data) {
        this.data = data;
    }
}

4.2 设计请求

接下来该向后端服务器发送请求以把用户数据插入到数据库,设计发送请求模块的第一步就是设计相关的请求

依据当前的业务功能模块进行请求的设计:

  • 请求路径:/users/reg
  • 请求参数:User user
  • 请求类型:POST
  • 响应结果:JsonResult<void>

4.3 处理请求

创建一个控制层对应的UserController类,依赖于业务层的接口.编写完成后启动主服务验证一下

//@RequestMapping("users")
@RestController//RestController=@RequestMapping+@RequestBody
@RequestMapping("/users")
/**
 * 这里继承BaseController表示:可以处理异常类
 */
public class UserController extends BaseController {

    @Autowired
    private IUserService userService;

      @GetMapping("/reg") //@RequestBody//表示此方法的响应结果以json格式进行数据的1响应给前端
      public JsonResult<Void> reg(User user) {
      //创建响应结果对象
      JsonResult<Void> result = new JsonResult<>();
      try {
      userService.reg(user);
      result.setState(200);
      result.setMessage("用户注册成功");
      } catch (UsernameDuplicatedException e) {
      result.setState(4000);
      result.setMessage("用户名被占用");
      } catch (InsertException e) {
      result.setState(5000);
      result.setMessage("注册时产生未知的异常");
      }
      return result;
      }
}

4.4 控制层优化设计


凡是业务层抛出的异常我们都在控制层进行了捕获,如果其他的业务模块也抛用户名被占用或者插入时异常,那么抛出异常的代码就要重复编写

优化方法:在控制层抽离出一个BaseController父类,在这个父类中统一处理关于异常的相关操作,优化如下:

1.在controller包下创建UserController类作为控制层下类的基类,用来做统一的异常捕获:

public class BaseController {

    //操作成功的状态码
    public static final int OK = 200;

    /**
     * 1.@ExceptionHandler表示该方法用于处理捕获抛出的异常
     * 2.什么样的异常才会被这个方法处理呢?所以需要ServiceException.class,这样的话只要是抛出ServiceException异常就会被拦截到handleException方法,此时handleException方法就是请求处理方法,返回值就是需要传递给前端的数据
     * 3.被ExceptionHandler修饰后如果项目发生异常,那么异常对象就会被自动传递给此方法的参数列表上,所以形参就需要写Throwable e用来接收异常对象
     */
    @ExceptionHandler(ServiceException.class)
    public JsonResult<Void> handleException(Throwable e) {
        JsonResult<Void> result = new JsonResult<>(e);
        if (e instanceof UsernameDuplicatedException) {
            result.setState(4000);
            result.setMessage("用户名已经被占用");
        } else if (e instanceof InsertException) {
            result.setState(5000);
            result.setMessage("插入数据时产生未知的异常");
        }
        return result;
    }
}

2.让UserController继承BaseController并重构UserController下的reg方法使该方法只需要关注请求处理而不再需要关注异常捕获:

    /**
     * 1.接收数据方式:请求处理方法的参数列表设置为pojo类型来接收前端的数据
     * SpringBoot会将前端url地址中的参数名和pojo类的属性名进行比较,如果这两个名称相同,
     * 则将值注入到pojo类中对于的属性上
     * @param user
     * @return
     */
    @PostMapping("/reg")
    //@RequestBody//表示此方法的响应结果以json格式进行数据的1响应给前端
    public JsonResult<Void> reg(User user) {
        userService.reg(user);
        return new JsonResult<>(OK);
    }

5.前端页面

1 熟悉ajax

1.什么是ajax函数?

这是jQuery封装的一个函数,称为$.ajax()函数,通过对象调用ajax()函数用来异步加载相关的请求.依靠的是JavaScript提供的一个对象:XHR(全称XmlHttpResponse)

2. ajax()函数的语法结构:

  • 使用ajax()时需要传递一个方法体作为方法的参数来使用(一对大括号就是一个方法体)
  • ajax接受多个参数时,参数与参数之间使用","分割
  • 每一组参数之间使用":"进行分割
  • 参数的组成部分一个是参数的名称(不能随便定义),另一个是参数的值(必须用字符串来表示)
  • 参数的声明顺序没有要求
$.ajax({
    url: "",
    type: "",
    data: "",
    dataType: "",
    success: function() {
        
    },
    error: function() {
        
    }
});

3.ajax()函数参数的含义:

2前端js编写

js代码可以独立声明在一个js文件里或者声明在一个script标签中.现在我们在register.html中编写js代码,js代码可以放在head标签中,也可以放在body标签中,可以放在任意一个位置,只要被script标签包裹就行了,这里我们放在整个body结束之前:

        <script>
            //1.监听注册按钮是否被点击,如果被点击可以执行一个方法(这里不能像ajax函数那样删去function()只留下{},这是官方规定的!)
            $("#btn-reg").click(function () {

                //let username = $("#username").val();
                //let pwd = $("#password").val();
                //上面这两行是动态获取表单中控件的数据,但是如果这样获取的话ajax函数中
                //就是data: "username="+username + "&password="+pwd,但太麻烦了,如
                // 果这个表单提交的是用户的兴趣爱好,那数据就很多了,一个表单20个数据都很正
                // 常,如果此时还用这种方式就太麻烦了,所以不建议用这种方式

                //2.发送ajax()的异步请求来完成用户的注册功能
                $.ajax({
                    url: "/users/reg",
                    type: "POST",

                    //serialize这个API会自动检测该表单有什么控件,每个控件检测后还会获取每个控
                    // 件的值,拿到这个值后并自动拼接成形如username=Tom&password=123的结构
                    data: $("#form-reg").serialize(),

                    dataType: "JSON",
                    success: function (json) { //1.js是弱数据类型,这个地方不用声明json的数据类型
                        //2.如果服务器成功响应就会将返回的数据传给形参,比如{state: 4000,message: "用户名
                        // 已经被占用",data: null}
                        if (json.state == 200) {
                            alert("注册成功")
                        } else {
                            alert("注册失败")
                        }
                    },
                    error: function (xhr) { //如果问题不在可控范围内,服务器就不会返回自己定
                        //义的json字符串:{state: 4000,message: "用户名已经被占用",data: null}
                        //而是返回一个XHR类型的对象,该对象也有一个状态码名字是status
                        alert("注册时产生未知的错误!"+xhr.status);
                    }
                });
            });
        </script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/976596.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

S7-1500/ET200MP 使用 TIA STEP7 进行自由口通讯

1. 硬件列表 2. 组态和配置 1) 新建项目 2) 创建CPU1500站点 3) 组态CM PtP 串口 4) 设置协议自由口 3. 编写通信程序 1) 逻辑地址的填写 2) 调用发送接收功能块 3) 创建发送DB块和接收DB块 4. 设备连接 5. 通信测试 1) 设置串口调试调试软件SSCOM32 2)…

某米ax3000路由器组网解析

我们使用某米k60手机与某米ax3000 wifi6路由器组网&#xff0c;来分析和学习网络速率与瓶颈限制。 某米 AX3000 路由器简介 某米 AX3000 路由器是一款支持 WiFi 6 的双频路由器&#xff0c;它的 MIMO 是 22&#xff0c;也就是两根天线。MIMO 是 Multiple Input Multiple Outpu…

[hpsupport@privatemail.com].Elbie勒索病毒的最新威胁:如何恢复您的数据?

引言&#xff1a; 随着技术的不断发展&#xff0c;网络犯罪分子也在不断进化和改进他们的方法&#xff0c;其中之一就是恶名昭著的勒索病毒。最近&#xff0c;出现了一种新的威胁&#xff0c;名为 [ hpsupportprivatemail.com ].Elbie 勒索病毒。让我们一起深入探索这个威胁&am…

拥抱国产化,生态软件信创兼容适配之路

国产化是指技术引进项目投产后所生产的产品中&#xff0c;国内生产件的数量占整件产品生产件数量。换句话说&#xff0c;软件国产化的占比&#xff0c;直接影响到技术是否会在某一个时点上被”卡脖子“。 随着国家经济的发展和技术水平的提高&#xff0c;国家整体实力大大增强…

视频集中存储/直播点播平台EasyDSS点播文件分类功能新升级

视频推拉流EasyDSS视频直播点播平台&#xff0c;集视频直播、点播、转码、管理、录像、检索、时移回看等功能于一体&#xff0c;可提供音视频采集、视频推拉流、播放H.265编码视频、存储、分发等视频能力服务。 TSINGSEE青犀视频的EasyDSS平台具有点播文件分类展示方法&#xf…

深入synchronized

##深入synchronized 2.1 类锁、对象锁 synchronized的使用一般就是同步方法和同步代码块。 synchronized的锁是基于对象实现的。 如果使用同步方法 static&#xff1a;此时使用的是当前类.class作为锁&#xff08;类锁&#xff09; 非static&#xff1a;此时使用的是当前对…

【网络安全带你练爬虫-100练】第23练:文件内容的删除+写入

目录 0x00 前言&#xff1a; 0x02 解决&#xff1a; 0x00 前言&#xff1a; 本篇博文可能会有一点点的超级呆 0x02 解决&#xff1a; 你是不是也会想&#xff1a; 使用pyrhon将指定文件夹位置里面的1.txt中数据全部删除以后---->然后再将参数req_text的值写入到1.txt …

【C++】反向迭代器精讲(以lIst为例)

目录 二&#xff0c;全部代码 三&#xff0c;设计思路 1. 讨论 2. 关于迭代器文档一个小细节 结语 一&#xff0c;前言 如果有小伙伴还未学习普通迭代器&#xff0c;请参考这篇文章中的普通迭代器实现。 【STL】list用法&试做_底层实现_花果山~~程序猿的博客-CSDN…

Android架构 架构和 CPU ABI - NDK

查看设备架构 adb -s emulator-5554 shell getprop ro.product.cpu.abi C:\Users\liyd>adb -s emulator-5554 shell getprop ro.product.cpu.abi x86_64C:\Users\liyd>adb -s 804c11f1 shell getprop ro.product.cpu.abi arm64-v8amumu模拟器12 C:\Users\liyd>adb …

MobaXterm 突破14个session限制

通常情况下&#xff1a;随着工作时间的增长&#xff0c;我们会保存许许多多的linux到本地的mobastream&#xff0c;然后当超过14个&#xff0c;就会被被限制&#xff0c;这个会让人很头疼。 1. 安装python&#xff0c;配置好环境变量 测试安装成功&#xff1a; 2. 基于项目进行…

uniapp点击事件在小程序中无法传参

这个问题很是神奇&#xff0c;第一次遇到。在h5中&#xff0c;点击事件可以正常传参&#xff0c;打包小程序后确失效了。 修改&#xff1a;for循环中的key&#xff0c;使用 index就好了

视频汇聚/视频云存储/视频监控管理平台EasyCVR启动时打印starting server:listen tcp,该如何解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;可实现视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、H.265自动转码H.264、平台级联等。为了便于用户二次开发、调用与集成&#xff0c;…

SpringBoot集成redis-Jedis

文章目录 1.相关概念2.环境搭建及测试 1.相关概念 Springboot学习笔记&#xff1a;https://blog.csdn.net/meini32/article/details/132544107 Redis快速入门&#xff1a;https://blog.csdn.net/meini32/article/details/132666283 2.环境搭建及测试 redis相关配置 Sprin…

车载域控制器DCU浪涌防护推荐TVS二极管

为了解决分布式EEA的这些问题&#xff0c;汽车工程师开始逐渐把很多功能相似、分离的ECU功能集成整合到一个比ECU性能更强的处理器硬件平台上&#xff0c;这就是汽车“域控制器&#xff08;Domain Controller Unit&#xff0c;DCU&#xff09;”。车载域控制器DCU大大优化整车的…

【Flink】关于jvm元空间溢出,mysql binlog冲突的问题解决

问题一&#xff1a;7张表是同一个mysql中的&#xff0c;我们进行增量同步时分别用不同的flink任务读取&#xff0c;造成mysql server-id冲突问题&#xff0c;如下&#xff1a; Caused by: io.debezium.DebeziumException: A slave with the same server_uuid/server_id as this…

LINUX内核启动流程-1

1、BIOS启动 硬件设置从OXFFFF0启动:CPU硬件设置加电即进入16位实模式状态运行,CPU硬件逻辑设计为加电瞬间强行将CS的值置为oxF000,IP的值置为0xFFF0,这样CS:IP就指向0xFFFF0这个地址位置。 BIOS程序的入口地址恰恰就是0xFFFF0 ! 也就是说,BIOS程序的第一条指令就设计在…

【0220】stats collector如何得知pgStatSock中的消息类型、消息报文内容以及消息是否完整?

1. vacuum、writer、checkpointer等进程如何发送统计信息给stats collector 前面已经图文并茂的讲解过,stats collector进程通过UDP方式与其他进程进行通信,在初始化资源时,通过socket()系统函数得到一个全局套接字fd。后续其他进程有统计消息时,通过该句柄,可发送消息给…

sql-gen:点击生成SQL、RO、VO的工具

sql-gen仓库地址&#xff1a;码云 Github 1. 概述 sql-gen是一个用于提高后端接口开发效率的小工具&#xff0c;主要有如下功能&#xff1a; 生成连表SQL语句根据WHERE条件来生成封装查询条件的实体类&#xff08;RO&#xff09;根据SELECT列来生成封装查询结果的实体类&…

学习笔记|小数点控制原理|数码管动态显示|段码跟位码|STC32G单片机视频开发教程(冲哥)|第十集:数码管动态显示

文章目录 1.数码管动态刷新的原理2.动态刷新原理3.8位数码管同时点亮新建一个数组选择每个位需要显示的内容实战小练&#xff1a;简易10秒免单计数器将刷新动作写成函数 课后练习: 1.数码管动态刷新的原理 上述图片引用自&#xff1a;51单片机初学2-数码管动态扫描 用一排端口来…

追求数学之美

菲尔兹奖得主玛丽安米尔札哈尼说过&#xff1a;“只有在那些最有耐心的信徒面前&#xff0c;数学才会展现出它美丽的一面。”她的意思是&#xff0c;数学之美的绽放通常需要一定的时间。有时你需要费上一番功夫才能欣赏到建筑的美。数学的美也是这样&#xff0c;只要你拥有足够…