java后端学习知识点

前情提要:这是博主学习的笔记,不专业

知识点一:公共字段自动填充

它的作用:

当代码的几个模块拥有相同的操作时,比如说在mapper层中不同mapper接口更新某个相同名称的属性时,可以把这段更新代码整合在一起变成公共字段

具体流程如下:

1.先自定义注解:

@Target:用于描述注解的使用范围

ElementType.METHOD应用于方法

@Retention:表明该注解的生命周期

RetentionPolicy.RUNTIME由JVM 加载,包含在类文件中,在运行时可以被获取到
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    //数据库操作类型:UPDATE,INSERT
    OperationType value();
}

2.基于Spring AOP的切面(Aspect),用于在特定方法执行前(前置通知)自动填充实体对象的公共字段。

@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    //切入点
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void pointcut() {}

    //before是前置通知,在通知中进行公共字段的赋值。
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        log.info("开始进行公共字段的填充...");

        //获取当前被拦截的方法上的数据库操作类型
        MethodSignature signature=(MethodSignature) joinPoint.getSignature();//方法签名对象
        AutoFill autoFill=signature.getMethod().getAnnotation(AutoFill.class);//获取方法上的注解对象
        OperationType operationType=autoFill.value();//获取数据库操作类型

        //获取到当前被拦截的方法的参数--实体对象
        Object[] args = joinPoint.getArgs();
        if(args==null|| args.length==0){
            return;
        }
        Object entity=args[0];

        //准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long CurrentId= BaseContext.getCurrentId();



        //根据当前不同的操作类型,为对应的属性通过反射来赋值
        if(operationType==OperationType.INSERT){
            try{
                Method setCreateTime =entity.getClass().getDeclaredMethod("setCreateTime",LocalDateTime.class);
                Method setCreateUser =entity.getClass().getDeclaredMethod("setCreateUser",Long.class);
                Method setUpdateTime =entity.getClass().getDeclaredMethod("setUpdateTime",LocalDateTime.class);
                Method setUpdateUser =entity.getClass().getDeclaredMethod("setUpdateUser",Long.class);

                //通过反射为对象属性赋值
                setCreateTime.invoke(entity,now);
                setCreateUser.invoke(entity,CurrentId);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,CurrentId);

            }catch (Exception e){
                e.printStackTrace();
            }


        }else if(operationType==OperationType.UPDATE){
            //为2个公共字段赋值
            try{
                Method setUpdateTime =entity.getClass().getDeclaredMethod("setUpdateTime",LocalDateTime.class);
                Method setUpdateUser =entity.getClass().getDeclaredMethod("setUpdateUser",Long.class);

                //通过反射为对象属性赋值
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,CurrentId);

            }catch (Exception e){
                e.printStackTrace();
            }
        }


    }
}

反射:

  1. entity.getClass().getDeclaredMethod(String name, Class<?>... parameterTypes)

    • entity.getClass():获取实体对象的类对象。
    • getDeclaredMethod:根据方法名和参数类型获取方法对象。
    • 第一个参数是方法名,如 "setCreateTime"
    • 第二个参数是方法参数类型,这里是 LocalDateTime.class 或 Long.class,表示方法的参数类型。

    这些代码片段通过反射获取了当前实体类中名为 setCreateTimesetCreateUsersetUpdateTimesetUpdateUser 的方法对象。

  2. setCreateTime.invoke(entity, now)
    • setCreateTime 是前面获取的方法对象。
    • invoke 方法用于调用这个方法。
    • 第一个参数 entity 是要调用方法的对象实例。
    • 第二个参数 now 是要传递给方法的参数(这里是当前时间 LocalDateTime 类型的对象)。

知识点二:捕获异常

/**
 * 全局异常处理器,处理项目中抛出的业务异常
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 捕获业务异常
     * @param ex
     * @return
     */
    @ExceptionHandler
    public Result exceptionHandler(BaseException ex){
        log.error("异常信息:{}", ex.getMessage());
        return Result.error(ex.getMessage());
    }

    @ExceptionHandler
    public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
        String message = ex.getMessage();
        if (message.contains("Duplicate key")){
            String[] split = message.split(" ");
            String username = split[2];
            String msg=username+ MessageConstant.ALREADY_EXISTS;
            return Result.error(msg);
        }else{
            return Result.error(MessageConstant.UNKNOWN_ERROR);
        }
    }

}
  • @ExceptionHandler:同样的注解,这里用来捕获SQLIntegrityConstraintViolationException类型的异常。
  • message:获取异常的消息内容。
  • if (message.contains("Duplicate key")):检查异常消息中是否包含"Duplicate key",这通常表明数据库操作试图插入一个已存在的唯一键值。
    • String[] split = message.split(" ");:将异常消息按空格拆分成字符串数组。
    • String username = split[2];:从拆分后的数组中提取特定位置的字符串,这里假设是用户名(实际情况需要根据具体的异常消息格式调整)。
    • String msg = username + MessageConstant.ALREADY_EXISTS;:构造用户友好的错误消息,MessageConstant.ALREADY_EXISTS可能是一个常量,表示某条记录已经存在。
    • return Result.error(msg);:返回包含错误信息的Result对象。
  • else:如果异常消息不包含"Duplicate key",则返回一个通用的未知错误信息。
    • return Result.error(MessageConstant.UNKNOWN_ERROR);:返回通用错误信息。

知识点三:比较散的知识点

1.mybatis中的useGeneratedKeys

<insert id="insert" useGeneratedKeys="true" keyProperty="id">
  1. useGeneratedKeys="true"

    • 这个属性表示MyBatis在执行插入操作时会自动获取数据库生成的主键值(通常是自增ID)。这个特性对使用自增主键的表特别有用,因为它可以避免手动获取生成的主键。
  2. keyProperty="id"

    • 这个属性指定了实体类中的哪个属性用于存储数据库生成的主键值。在插入记录后,MyBatis会将生成的主键值填充到指定的属性中。

        使用:当service层需要mapper层结束后的数据时使用,如下:


dishMapper.insert(dish);
Long id = dish.getId();

2.mybatis的动态标签<foreach>

<foreach collection="flavors" item="df" separator=",">
    (#{df.dishId},#{df.name},#{df.value})
</foreach>

表示遍历flavors这个ListSet或者其他类型的集合,其中每一个元素(自定义)叫做df,每个生成的SQL片段之间会用逗号 , 分隔。还有open和close标签指定在遍历集合生成的SQL片段前后添加的字符,通过是和sql的in一起使用,如下:

        select setmeal_id from setmeal_dish where dish_id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>

3.分页查询-pagehelper

1.首先在pom.xml文件中导入相关依赖

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
        </dependency>

2.在service中使用

    public PageResult page(DishPageQueryDTO dishPageQueryDTO) {
        PageHelper.startPage(dishPageQueryDTO.getPage(),dishPageQueryDTO.getPageSize());
        Page<DishVO> page=dishMapper.page(dishPageQueryDTO);
        return new PageResult(page.getTotal(),page.getResult());
    }

pagehelper是把mapper层中的相关查询自动添加了limit * *,所以在相关mapper层中不需要在添加该SQL命令。pageResult是自定义类,格式如下:

知识点四:注解

1.@RequestParam

@RequestParam注解有以下属性:

value:请求参数的名称。如果请求参数的名称与方法参数的名称相同,则该属性可以省略。

required:指定请求参数是否是必需的,默认为true。如果设置为false,则表示该参数是可选的。

defaultValue:指定当请求参数未提供时使用的默认值。

用途:

可以用在路径参数上:

@GetMapping("/users/{id}")
public User getUser(@RequestParam("id") Long userId) {
    // 方法体
}

可以用在普通参数上,若是请求参数是字符串,但是接收参数是列表不同类型的,RequestParam可以自动转化(下图前端传入的是ids字符串(类似"1,2,3"),但是后端接收参数是List类型的):

    @DeleteMapping
    @ApiOperation("删除菜品")
    public Result delete(@RequestParam List<Long> ids){
        log.info("菜品批量删除{}",ids);
        dishService.delete(ids);
        return Result.success();
    }

2.@Configuration

1.告诉spring这是一个配置类,相当于spring的xml配置文件

2.被@Configuration 注解的类,会被cglib代理进行增强

3.@Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系,保证@Bean的对象作用域受到控制,避免多例

知识点五:配置阿里云OSS

在application.yml配置:

在application-dev.yml配置:

创建一个配置类AliOssProperties:

@Component
@ConfigurationProperties(prefix = "sky.alioss")
@Data
public class AliOssProperties {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

}

创建一个工具类AliOssUtil:

@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

    /**
     * 文件上传
     *
     * @param bytes
     * @param objectName
     * @return
     */
    public String upload(byte[] bytes, String objectName) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);

        log.info("文件上传到:{}", stringBuilder.toString());

        return stringBuilder.toString();
    }
}

给上面的工具类配置属性:

@Slf4j
@Configuration
public class OssConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties) {
        log.info("开始创建阿里云文件上传工具类{}", aliOssProperties);
        return new AliOssUtil(aliOssProperties.getEndpoint(),
                aliOssProperties.getAccessKeyId(),
                aliOssProperties.getAccessKeySecret(),
                aliOssProperties.getBucketName());
    }
}

  • 49
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料 python面试题、知识点,用于程序员应聘学习参考,提供代码+题型等资料
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值