架构师课程笔记day03——单体应用开发过程中常用知识点及注意事项

news2024/9/27 9:25:24

1.自定义异常捕获处理

定义如下类 可捕获并处理相关异常

package com.imooc.exception;

import com.imooc.utils.IMOOCJSONResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

@RestControllerAdvice
public class CustomExceptionHandler {

    // 上传文件超过500k,捕获异常:MaxUploadSizeExceededException
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public IMOOCJSONResult handlerMaxUploadFile(MaxUploadSizeExceededException ex) {
        return IMOOCJSONResult.errorMsg("文件上传大小不能超过500k,请压缩图片或者降低图片质量再上传!");
    }


//    // 上传文件超过500k,捕获异常:MaxUploadSizeExceededException
//    @ExceptionHandler(MyTestException.class)
//    public IMOOCJSONResult handlerMaxUploadFile(MyTestException ex) {
//        return IMOOCJSONResult.errorMsg("错错错 是我的错");
//    }
}

2.脱敏

某些私密信息 如手机号 邮箱等 需要脱敏 如下是示例

package com.imooc.utils;

import sun.applet.Main;

/**
 * 通用脱敏工具类
 * 可用于:
 *      用户名
 *      手机号
 *      邮箱
 *      地址等
 */
public class DesensitizationUtil {

    private static final int SIZE = 6;
    private static final String SYMBOL = "*";

    public static void main(String[] args) {
        String name = commonDisplay("慕课网");
        String mobile = commonDisplay("13900000000");
        String mail = commonDisplay("admin@imooc.com");
        String address = commonDisplay("北京大运河东路888号");

        System.out.println(name);
        System.out.println(mobile);
        System.out.println(mail);
        System.out.println(address);
    }

    /**
     * 通用脱敏方法
     * @param value
     * @return
     */
    public static String commonDisplay(String value) {
        if (null == value || "".equals(value)) {
            return value;
        }
        int len = value.length();
        int pamaone = len / 2;
        int pamatwo = pamaone - 1;
        int pamathree = len % 2;
        StringBuilder stringBuilder = new StringBuilder();
        if (len <= 2) {
            if (pamathree == 1) {
                return SYMBOL;
            }
            stringBuilder.append(SYMBOL);
            stringBuilder.append(value.charAt(len - 1));
        } else {
            if (pamatwo <= 0) {
                stringBuilder.append(value.substring(0, 1));
                stringBuilder.append(SYMBOL);
                stringBuilder.append(value.substring(len - 1, len));

            } else if (pamatwo >= SIZE / 2 && SIZE + 1 != len) {
                int pamafive = (len - SIZE) / 2;
                stringBuilder.append(value.substring(0, pamafive));
                for (int i = 0; i < SIZE; i++) {
                    stringBuilder.append(SYMBOL);
                }
                if ((pamathree == 0 && SIZE / 2 == 0) || (pamathree != 0 && SIZE % 2 != 0)) {
                    stringBuilder.append(value.substring(len - pamafive, len));
                } else {
                    stringBuilder.append(value.substring(len - (pamafive + 1), len));
                }
            } else {
                int pamafour = len - 2;
                stringBuilder.append(value.substring(0, 1));
                for (int i = 0; i < pamafour; i++) {
                    stringBuilder.append(SYMBOL);
                }
                stringBuilder.append(value.substring(len - 1, len));
            }
        }
        return stringBuilder.toString();
    }

}

3.springboot自带定时任务的优劣

优点:

简单易用

缺点:

    /**
     * 使用定时任务关闭超期未支付订单,会存在的弊端:
     * 1. 会有时间差,程序不严谨
     *      10:39下单,11:00检查不足1小时,12:00检查,超过1小时多余39分钟
     * 2. 不支持集群
     *      单机没毛病,使用集群后,就会有多个定时任务
     *      解决方案:只使用一台计算机节点,单独用来运行所有的定时任务
     * 3. 会对数据库全表搜索,及其影响数据库性能:select * from order where orderStatus = 10;
     * 定时任务,仅仅只适用于小型轻量级项目,传统项目
     *
     * 后续课程会涉及到消息队列:MQ-> RabbitMQ, RocketMQ, Kafka, ZeroMQ...
     *      延时任务(队列)
     *      10:12分下单的,未付款(10)状态,11:12分检查,如果当前状态还是10,则直接关闭订单即可
     */

在线Cron表达式生成器

package com.imooc.config;

import com.imooc.service.OrderService;
import com.imooc.utils.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class OrderJob {

    @Autowired
    private OrderService orderService;


//    @Scheduled(cron = "0/3 * * * * ?")
//    @Scheduled(cron = "0 0 0/1 * * ?")
    public void autoCloseOrder() {
        orderService.closeOrder();
        System.out.println("执行定时任务,当前时间为:"
                + DateUtil.getCurrentDateString(DateUtil.DATETIME_PATTERN));
    }

}

4.jsr303 hibernate validator 参数校验

jsr303是个规范 这里我们使用的实现框架是 hibernate validator 

如下依赖中自带


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

  需要被校验的BO类

package com.imooc.pojo.bo.center;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.*;
import java.util.Date;

@ApiModel(value="用户对象", description="从客户端,由用户传入的数据封装在此entity中")
public class CenterUserBO {

    /**
     * Bean Validation 中内置的 constraint
     * @Null 被注释的元素必须为 null
     * @NotNull 被注释的元素必须不为 null
     * @AssertTrue 被注释的元素必须为 true
     * @AssertFalse 被注释的元素必须为 false
     * @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
     * @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
     * @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
     * @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
     * @Size(max=, min=) 被注释的元素的大小必须在指定的范围内
     * @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
     * @Past 被注释的元素必须是一个过去的日期
     * @Future 被注释的元素必须是一个将来的日期
     * @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
     * Hibernate Validator 附加的 constraint
     * @NotBlank(message =) 验证字符串非null,且长度必须大于0
     * @Email 被注释的元素必须是电子邮箱地址
     * @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
     * @NotEmpty 被注释的字符串的必须非空
     * @Range(min=,max=,message=) 被注释的元素必须在合适的范围内
     */

    @ApiModelProperty(value="用户名", name="username", example="json", required = false)
    private String username;
    @ApiModelProperty(value="密码", name="password", example="123456", required = false)
    private String password;
    @ApiModelProperty(value="确认密码", name="confirmPassword", example="123456", required = false)
    private String confirmPassword;


    @NotBlank(message = "用户昵称不能为空")
    @Length(max = 12, message = "用户昵称不能超过12位")
    @ApiModelProperty(value="用户昵称", name="nickname", example="杰森", required = false)
    private String nickname;

    @Length(max = 12, message = "用户真实姓名不能超过12位")
    @ApiModelProperty(value="真实姓名", name="realname", example="杰森", required = false)
    private String realname;

    @Pattern(regexp = "^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\\d{8})$", message = "手机号格式不正确")
    @ApiModelProperty(value="手机号", name="mobile", example="13999999999", required = false)
    private String mobile;

    @Email
    @ApiModelProperty(value="邮箱地址", name="email", example="imooc@imooc.com", required = false)
    private String email;

    @Min(value = 0, message = "性别选择不正确")
    @Max(value = 2, message = "性别选择不正确")
    @ApiModelProperty(value="性别", name="sex", example="0:女 1:男 2:保密", required = false)
    private Integer sex;
    @ApiModelProperty(value="生日", name="birthday", example="1900-01-01", required = false)
    private Date birthday;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getConfirmPassword() {
        return confirmPassword;
    }

    public void setConfirmPassword(String confirmPassword) {
        this.confirmPassword = confirmPassword;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getRealname() {
        return realname;
    }

    public void setRealname(String realname) {
        this.realname = realname;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "CenterUserBO{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", confirmPassword='" + confirmPassword + '\'' +
                ", nickname='" + nickname + '\'' +
                ", realname='" + realname + '\'' +
                ", mobile='" + mobile + '\'' +
                ", email='" + email + '\'' +
                ", sex=" + sex +
                ", birthday=" + birthday +
                '}';
    }
}

 controller类中的方法 可以看到 要校验该BO参数只需要加上@valid注解然后 加上一个

BindingResult result 参数 然后 判断是否通过校验 再进行相应返回

   @ApiOperation(value = "修改用户信息", notes = "修改用户信息", httpMethod = "POST")
    @PostMapping("update")
    public IMOOCJSONResult update(
            @ApiParam(name = "userId", value = "用户id", required = true)
            @RequestParam String userId,
            @RequestBody @Valid CenterUserBO centerUserBO,
            BindingResult result,
            HttpServletRequest request, HttpServletResponse response) {

        // 判断BindingResult是否保存错误的验证信息,如果有,则直接return
        if (result.hasErrors()) {
//            Map<String, String> errorMap = getErrors(result);
//            return IMOOCJSONResult.errorMap(errorMap);
            return IMOOCJSONResult.errorMsg(result.getFieldErrors().get(0).getDefaultMessage());
        }

        Users userResult = centerUserService.updateUserInfo(userId, centerUserBO);

        userResult = setNullProperty(userResult);
        CookieUtils.setCookie(request, response, "user",
                JsonUtils.objectToJson(userResult), true);

        // TODO 后续要改,增加令牌token,会整合进redis,分布式会话

        return IMOOCJSONResult.ok();
    }

5.文件上传基本流程

定义上传相关的路径信息

package com.imooc.resource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "file")
@PropertySource("classpath:file-upload-dev.properties")
public class FileUpload {

    private String imageUserFaceLocation;
    private String imageServerUrl;

    public String getImageServerUrl() {
        return imageServerUrl;
    }

    public void setImageServerUrl(String imageServerUrl) {
        this.imageServerUrl = imageServerUrl;
    }

    public void setImageUserFaceLocation(String imageUserFaceLocation) {
        this.imageUserFaceLocation = imageUserFaceLocation;
    }

    public String getImageUserFaceLocation() {
        return imageUserFaceLocation;
    }
}

file-upload-dev.properties

file.imageUserFaceLocation=\\workspaces\\images\\foodie\\faces
file.imageServerUrl=http://localhost:8088/foodie/faces

上传 后端示例代码

主要分为如下几步

校验大小及后缀,

文件名生成 这个记得要在里面加个用户id 或者订单id啥的 后面方便找或者删

生成文件

更新到数据库

package com.imooc.controller.center;

import com.imooc.controller.BaseController;
import com.imooc.exception.MyTestException;
import com.imooc.pojo.Users;
import com.imooc.pojo.bo.center.CenterUserBO;
import com.imooc.resource.FileUpload;
import com.imooc.service.UserService;
import com.imooc.service.center.CenterUserService;
import com.imooc.utils.CookieUtils;
import com.imooc.utils.DateUtil;
import com.imooc.utils.IMOOCJSONResult;
import com.imooc.utils.JsonUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Api(value = "用户信息接口", tags = {"用户信息相关接口"})
@RestController
@RequestMapping("userInfo")
public class CenterUserController extends BaseController {

    @Autowired
    private CenterUserService centerUserService;

    @Autowired
    private FileUpload fileUpload;

    @ApiOperation(value = "用户头像修改", notes = "用户头像修改", httpMethod = "POST")
    @PostMapping("uploadFace")
    public IMOOCJSONResult uploadFace(
            @ApiParam(name = "userId", value = "用户id", required = true)
            @RequestParam String userId,
            @ApiParam(name = "file", value = "用户头像", required = true)
            MultipartFile file,
            HttpServletRequest request, HttpServletResponse response) {

        // .sh .php

        // 定义头像保存的地址
//        String fileSpace = IMAGE_USER_FACE_LOCATION;
        String fileSpace = fileUpload.getImageUserFaceLocation();
        // 在路径上为每一个用户增加一个userid,用于区分不同用户上传
        String uploadPathPrefix = File.separator + userId;

        // 开始文件上传
        if (file != null) {
            FileOutputStream fileOutputStream = null;
            try {
                // 获得文件上传的文件名称
                String fileName = file.getOriginalFilename();

                if (StringUtils.isNotBlank(fileName)) {

                    // 文件重命名  imooc-face.png -> ["imooc-face", "png"]
                    String fileNameArr[] = fileName.split("\\.");

                    // 获取文件的后缀名
                    String suffix = fileNameArr[fileNameArr.length - 1];

                    if (!suffix.equalsIgnoreCase("png") &&
                            !suffix.equalsIgnoreCase("jpg") &&
                            !suffix.equalsIgnoreCase("jpeg")) {
                        return IMOOCJSONResult.errorMsg("图片格式不正确!");
                    }

                    // face-{userid}.png
                    // 文件名称重组 覆盖式上传,增量式:额外拼接当前时间
                    String newFileName = "face-" + userId + "." + suffix;

                    // 上传的头像最终保存的位置
                    String finalFacePath = fileSpace + uploadPathPrefix + File.separator + newFileName;
                    // 用于提供给web服务访问的地址
                    uploadPathPrefix += ("/" + newFileName);

                    File outFile = new File(finalFacePath);
                    if (outFile.getParentFile() != null) {
                        // 创建文件夹
                        outFile.getParentFile().mkdirs();
                    }

                    // 文件输出保存到目录
                    fileOutputStream = new FileOutputStream(outFile);
                    InputStream inputStream = file.getInputStream();
                    IOUtils.copy(inputStream, fileOutputStream);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (fileOutputStream != null) {
                        fileOutputStream.flush();
                        fileOutputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        } else {
            return IMOOCJSONResult.errorMsg("文件不能为空!");
        }

        // 获取图片服务地址
        String imageServerUrl = fileUpload.getImageServerUrl();

        // 由于浏览器可能存在缓存的情况,所以在这里,我们需要加上时间戳来保证更新后的图片可以及时刷新
        String finalUserFaceUrl = imageServerUrl + uploadPathPrefix
                 + "?t=" + DateUtil.getCurrentDateString(DateUtil.DATE_PATTERN);

        // 更新用户头像到数据库
        Users userResult = centerUserService.updateUserFace(userId, finalUserFaceUrl);

        userResult = setNullProperty(userResult);
        CookieUtils.setCookie(request, response, "user",
                JsonUtils.objectToJson(userResult), true);

        // TODO 后续要改,增加令牌token,会整合进redis,分布式会话

//        throw new MyTestException();
        return IMOOCJSONResult.ok();
    }


    private Map<String, String> getErrors(BindingResult result) {
        Map<String, String> map = new HashMap<>();
        List<FieldError> errorList = result.getFieldErrors();
        for (FieldError error : errorList) {
            // 发生验证错误所对应的某一个属性
            String errorField = error.getField();
            // 验证错误的信息
            String errorMsg = error.getDefaultMessage();

            map.put(errorField, errorMsg);
        }
        return map;
    }

    private Users setNullProperty(Users userResult) {
        userResult.setPassword(null);
        userResult.setMobile(null);
        userResult.setEmail(null);
        userResult.setCreatedTime(null);
        userResult.setUpdatedTime(null);
        userResult.setBirthday(null);
        return userResult;
    }

}

6.mybatis  pagehelper分页注意事项

 前面几点都还好理解

最后一点 意思就是 比如当前 查询结果为订单VO 他又包含许多子订单项VO

分页条数为10 如果你想要页面分页的主体是订单 也就是一个页面 十个订单

 这个 时候mapper.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.imooc.mapper.OrdersMapperCustom" >

  <resultMap id="myOrdersVO" type="com.imooc.pojo.vo.MyOrdersVO">
    <id column="orderId" property="orderId"/>
    <result column="createdTime" property="createdTime"/>
    <result column="payMethod" property="payMethod"/>
    <result column="realPayAmount" property="realPayAmount"/>
      <result column="postAmount" property="postAmount"/>
      <result column="orderStatus" property="orderStatus"/>
      <result column="isComment" property="isComment"/>

    <collection property="subOrderItemList"
                select="getSubItems"
                column="orderId"
                ofType="com.imooc.pojo.vo.MySubOrderItemVO">
      <result column="itemId" property="itemId"/>
      <result column="itemName" property="itemName"/>
      <result column="itemImg" property="itemImg"/>
<!--        <result column="itemSpecId" property="itemSpecId"/>-->
        <result column="itemSpecName" property="itemSpecName"/>
        <result column="buyCounts" property="buyCounts"/>
        <result column="price" property="price"/>
    </collection>
  </resultMap>

  <select id="queryMyOrders" resultMap="myOrdersVO" parameterType="Map">
    SELECT
        od.id as orderId,
        od.created_time as createdTime,
        od.pay_method as payMethod,
        od.real_pay_amount as realPayAmount,
        od.post_amount as postAmount,
        os.order_status as orderStatus,
        od.is_comment as isComment
    FROM
        orders od
    LEFT JOIN
        order_status os
    on od.id = os.order_id
    WHERE
        od.user_id = #{paramsMap.userId}
    AND
        od.is_delete = 0
        <if test="paramsMap.orderStatus != null">
          and os.order_status = #{paramsMap.orderStatus}
        </if>
    ORDER BY
        od.updated_time ASC
  </select>
    
    
    <select id="getSubItems" parameterType="String" resultType="com.imooc.pojo.vo.MySubOrderItemVO">

      select
        oi.item_id as itemId,
        oi.item_name as itemName,
        oi.item_img as itemImg,
        oi.item_spec_name as itemSpecName,
        oi.buy_counts as buyCounts,
        oi.price as price
      from
        order_items oi
      where
        oi.order_id = #{orderId}

    </select>
    
</mapper>

7.环境切换spring.profile.active

比如我们想要配置不同环境的mysql 的url

不同环境给应用配置不同端口

还有mybatis的sql日志 生产环境没必要打印

如果在一个文件中改就很麻烦 

如果配置文件基本不改 当然可以设置gitignore然后 提交时不管

比如我们想在不同环境 配置不同的bean

都可以用到这玩意

配置切换示例

application.yml

spring:
  datasource: # 数据源的相关配置
      type: com.zaxxer.hikari.HikariDataSource # 数据源类型:HikariCP
      driver-class-name: com.mysql.jdbc.Driver # mysql驱动
      url: jdbc:mysql://49.235.78.53/foodie?useUnicode=true&useSSL=false&characterEncoding=UTF-8&autoReconnect
      username: root
      password: root
#  profiles:
#    active: dev

 application-dev.yml

server:
  port: 8088

spring:
  datasource:                                           # 数据源的相关配置
    url: jdbc:mysql://localhost:3306/foodie-shop-dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
    password: roota

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

  application-prod.yml

server:
  port: 80

spring:
  datasource:                                           # 数据源的相关配置
    url: jdbc:mysql://localhost:3306/foodie-shop-dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
    password: imooc

bean切换示例

SpringBoot配置文件中spring.profiles.active配置多个bean不同作用环境

8.云服务器端口开放

这里以腾讯云服务器举例 

点击查看详情

点击防火墙,然后添加对应规则 懒得话可以运行访问所有端口

 

9.jdk上传及环境变量配置

去下载 好后解压jdk
tar -zxvf jdk8.tar.gz

编辑profile文件 添加环境变量

vim /etc/profile

文件最后添加如下三行 /usr/java/jdk1.8.0_191 这个是根据你自己路径来

export JAVA_HOME=/usr/java/jdk1.8.0_191
export PATH=$JAVA_HOME/bin:$PATH 
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 

刷新配置

source /etc/profile

测试环境变量是否生效

java -version

10.部署咱们的单体应用项目并运行

添加这样一个war包的启动类

默认是jar包 后面整到微服务再换成jar

package com.imooc;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

// 打包war [4] 增加war的启动类
public class WarStarterApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        // 指向Application这个springboot启动类
        return builder.sources(Application.class);
    }
}

 打包方式改成war

 点击install 打包到本地

 可以看到 target目录下有这样一个war

上传两次tomcat 然后 解压然后改名 一个放前端项目 一个放后端项目

 把我们的war包上传解压 放到tomcat下webapps目录

 修改端口

修改好后启动startup.sh 然后测试 成功

 

 

前端项目部署就是直接 把对应俩项目拷贝到 tomcat-frontend下然后启动即可

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

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

相关文章

第十二篇 1+X考证 Web前端测试题PHP篇(新)

单选题 1、以下关于PHP面向对象的说法错误的是&#xff08; A &#xff09; A、PHP可以多重继承&#xff0c;一个类可以继承多个父类 B、PHP使用new运算符来获取一个实例对象 C、一个类可以在声明中用extends关键字继承另一个类的方法和属性 D、PHP默认将var关键字解释为pu…

数据源支持

数据源支持目录概述需求&#xff1a;设计思路实现思路分析1.AT模式2.TCC模式3.Saga模式4.XA模式参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for ch…

【ROS】—— ROS快速上手

文章目录前言1. ROS-melodic 安装2. ROS基本操作2.1 创建工作空间2.2 创建功能包2.3 HelloWorld(C版)2.4 HelloWorld(Python版)3. Vscode ROS 插件4. vscode 使用基本配置4.1 启动 vscode4.2 vscode 中编译 ros5. launch文件演示6. ROS文件系统7. ROS文件系统相关命令前言 &…

沸腾过程气泡成核OVITO渲染

《Lammps空间划分——识别气泡、三维裂隙》 根据博文对纳米气泡的筛选&#xff08;获得select&#xff09;&#xff0c;本案例练习如何渲染气泡。 文章目录一、选择气泡&#xff08;select&#xff09;二、删除液体三、渲染液体四、巧妙利用原子半径大小五、气泡渲染并获得体积…

elasticsearch 7.9.3知识归纳整理(一)之es,kibana,ik的下载安装

es&#xff0c;kibana&#xff0c;ik的下载安装 下载地址 es下载地址&#xff1a;https://www.elastic.co/cn/downloads/elasticsearch kibana下载地址&#xff1a; https://www.elastic.co/cn/downloads/kibana ik中文分词器下载地址&#xff1a;https://github.com/medcl/el…

我的周刊(第072期)

我的信息周刊&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。&#x1f3af; 项目duplicati[1]Duplicati 是一个免费的开源备份客户端…

力扣(LeetCode)364. 加权嵌套序列和 II(2022.12.31)

给你一个整数嵌套列表 nestedList &#xff0c;每一个元素要么是一个整数&#xff0c;要么是一个列表&#xff08;这个列表中的每个元素也同样是整数或列表&#xff09;。 整数的 深度 取决于它位于多少个列表内部。例如&#xff0c;嵌套列表 [1,[2,2],[[3],2],1] 的每个整数的…

回归原型网络代码episode数据加载

一般PyTorchPyTorchPyTorch加载数据的固定格式是: dataset MyDataset() : 构建DatasetDatasetDataset对象 dataLoader DataLoader(dataset) #通过DataLoaderDataLoaderDataLoader来构造迭代对象. num_epoches 100 for epoch in range(num_epoches): #逐步迭代数据 for img,l…

元宇宙产业委评选2022全球元宇宙十大事件(含国外元宇宙五大事件)

中国移动通信联合会元宇宙产业工作委员会&#xff08;简称为&#xff1a;元宇宙产业委&#xff09; 评选2022全球元宇宙十大事件&#xff08;含国外元宇宙五大事件&#xff09; 1、1月5日&#xff0c;CES 2022上&#xff0c;英伟达&#xff08;NVIDIA&#xff09;宣布旗下元宇…

【django】HttpRequest对象的属性和路由补充

文章目录一、HttpRequest对象的常用属性1、request.GET&#xff1a;获取查询字符串参数案例:特别注意&#xff1a;2、request.POST&#xff1a;post请求数据&#xff0c;只能获取表单参数3、request.body&#xff1a;请求body&#xff0c;响应结果为字节类型4、request.method&…

一文搞懂G1垃圾回收器

G1是从JDK9之后的默认垃圾回收器&#xff0c;其功能强大&#xff0c;性能优异&#xff0c;不过目前市面的材料不算多&#xff0c;很多都是抄来抄去&#xff0c;讲得也不太清楚。经过仔细阅读oracle官网以及相关的材料&#xff0c;从整体上梳理了G1的过程&#xff0c;希望这一文…

数据库设计规范详解

对于后端开发人员&#xff0c;建表是个基础活&#xff0c;是地基&#xff0c;如果地基不大牢固&#xff0c;后面在程序开发过程中会带来很多麻烦&#xff0c;在建表的时候不注意细节&#xff0c;等后面系统上线之后&#xff0c;表的维护成本变得非常高&#xff0c;而且很容易踩…

基数排序分析

&#x1f954; 原理介绍&#xff1a; [排序算法] 基数排序 (C) - Amαdeus - 博客园 前述的各类排序方法都是建立在关键字比较的基础上&#xff0c;而基数排序是一种非比较型整数排序算法。它的基本思想是将整数按位数切割成不同的数字&#xff0c;然后按每个位数分别比较。 …

单片机基础知识之定时计数器和寄存器

目录 一、定时计数器 二、什么是寄存器 三、定时器如何定时10毫秒 四、定时器编程前寄存器配置计划 五、编程定时器控制LED每隔一秒亮灭 一、定时计数器 1、定时计数器的概念引入 定时器和计数器&#xff0c;电路一样 定时或者计数的本质就是让单片机某个部件数数 当定…

Linux基础------高级IO

文章目录阻塞IO非阻塞IO信号驱动异步IO多路转接&#xff08;核心终点&#xff09;实际上 IO “等” 拷贝 等什么呢&#xff1f; -----> 等待的是内核将数据准备好。 拷贝-------> 数据从内核考到用户 IO话题&#xff1a; 无非就是 1 &#xff0c; 改变等的方式 2 &…

Linux中编译带kafka模块的搜狗workflow开源库

workflow依赖的第三方库 openssl https://github.com/openssl/openssl apt install libssl-dev zlib https://github.com/madler/zlib git clone https://github.com/madler/zlib.git./configuremake -j4 make install lz4 (版本>1.7.5) https://github.com/lz4/lz4 …

C语言:预处理(2)

宏通常被用于执行简单的运算。 宏相比于函数的优势&#xff1a; 1.用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。 2.更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的…

Diffusion Model原理详解及源码解析

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;专栏推荐&#xff1a;深度学习网络原理与实战 &#x1f34a;近期目标&#xff1a;写好专栏的每一篇文章 &#x1f34a;支持小苏&#xff1a;点赞&#x1f44d;&#x1f3fc;、…

KubeSphere中间件部署

目录 &#x1f9e1;应用部署总览 &#x1f9e1;中间件部署 MySQL有状态副本集 &#x1f360;KubeSphere创建配置集 &#x1f360;KubeSphere创建存储卷 &#x1f360;KubeSphere创建有状态副本集 &#x1f360;集群访问 &#x1f49f;这里是CS大白话专场&#xff0c;让枯…

Entity Framework Core 代码自动化迁移

简述 文章内容基于&#xff1a;.NET6 Entity Framewor kCore 7.0.* 使用 EF Core 进行 Code First 开发的时候&#xff0c;肯定会遇到将迁移更新到生产数据库这个问题&#xff0c;大多数都是使用命令生成迁移 SQL&#xff0c;然后使用 SQL 脚本将更新迁移到生产数据库的方式&a…