若依后端笔记

PageHelper和TableSupport都是用于处理分页查询的工具类,但它们有一些区别。

1.底层实现:PageHelper是一个功能强大且广泛使用的分页查询插件,主要用于集成持久层框架(如MyBatis)实现分页查询。它通过拦截器的方式拦截SQL语句并自动进行分页查询。TableSupport,则是一个封装和处理分页查询参数的工具类,用于在Java Servlet开发中处理分页查询参数。

2.依赖关系:PageHelper作为一个分页查询插件,需要与持久层框架(如MyBatis)进行集成使用,需要在项目中添加对PageHelper的依赖。而TableSupport是一个通用的工具类,可以直接在Java Servlet开发中使用,不需要额外的依赖。

3.功能范围:PageHelper提供了更为丰富和灵活的分页查询功能,支持动态排序、多个分页查询、多层嵌套查询等。它还可以与其他高级查询功能(如条件查询、关联查询)配合使用。TableSupport则更加简化,主要用于封装和处理分页查询参数,提供了获取当前页码、每页显示数量、排序参数等功能。

4.应用场景:PageHelper适用于需要在持久层框架中进行高级分页查询的情况,尤其是与MyBatis框架集成时。TableSupport则适用于需要在Java Servlet开发中进行简单的分页查询,用于处理分页查询参数的传递和获取。

总体而言,PageHelper适用于复杂的分页查询需求,尤其是在集成持久层框架时;而TableSupport则适用于简单的分页查询需求,特别是在Java Servlet开发中使用。选择使用哪个工具类,取决于具体的项目需求和开发场景。

对于日志的自定义注解,通常需要自己编写切面,原因如下:

1.自定义注解只是标记,不具备切面逻辑:自定义注解本身只是一个标记,指示哪些方法需要记录日志,但它本身并不能实现切面逻辑,即在目标方法执行前后进行日志记录。因此,需要编写切面来定义日志记录的具体逻辑。

2.日志记录与业务逻辑相分离:切面的作用是实现与业务逻辑相分离的横切关注点,并提供一种通用的方式来处理这些关注点。日志记录通常不仅仅是简单的打印一行日志,还可能涉及日志级别、日志内容格式化等复杂操作,因此将日志记录逻辑放在切面中,能够使业务逻辑更加清晰和干净。

3.切面提供了更多的灵活性:编写切面类可以更加灵活地控制日志记录的行为,例如可以根据注解的参数灵活地指定日志级别、自定义日志格式、记录的内容等。通过切面,可以根据具体需求定制日志记录的方式,而不是局限于自定义注解的设计。

综上所述,为了实现日志记录的具体逻辑以及提供更大的灵活性,通常需要自己编写切面来配合日志的自定义注解使用。

对于自定义Excel的实现,通常情况下不需要编写切面逻辑,原因如下:

1.Excel导出逻辑相对简单:相比于其他横切关注点,如日志记录、异常处理等,Excel导出逻辑相对来说相对简单。一般而言,Excel导出只涉及数据的提取和格式化操作,并不需要像日志记录那样进行复杂的切面处理。

2.切面对Excel导出的影响较小:Excel导出通常是在业务方法执行结束后进行的,而且对业务方法本身并没有特别的要求。因此,大部分情况下不需要使用切面来控制Excel导出的行为。

3.自定义Excel注解主要用于元数据的配置:自定义Excel注解一般是用于标记属性和字段的元数据,通过注解完成Excel导出时的表头、列名、样式等属性的定义。这些注解在Excel导出时仅起到元数据配置的作用,不需要切面来实现逻辑。

当然,如果你有特定的需求,比如需要在Excel导出前后进行一些额外的处理,例如权限验证、数据校验等,则可以考虑编写切面来实现这些功能。但一般情况下,自定义Excel不需要复杂的切面逻辑来实现导出功能。

shiro

特性:认证 授权 会话管理 加密

@Transactional注解坑点

坑点1:Spring的默认的事务规则是遇到运行异常(RuntimeException)和程序错误(Error)才会回滚。如果想针对检查异常进行事务回滚,可以在@Transactional注解里使用 rollbackFor属性明确指定异常。

@Transactional(rollbackFor = Exception.class)
public int insertUser(User user) throws Exception
{
	// 新增用户信息
	int rows = userMapper.insertUser(user);
	// 新增用户岗位关联
	insertUserPost(user);
	// 新增用户与角色管理
	insertUserRole(user);
	// 模拟抛出SQLException异常
	boolean flag = true;
	if (flag)
	{
		throw new SQLException("发生异常了..");
	}
	return rows;
}

坑点2: 在业务层捕捉异常后,发现事务不生效。 这是许多新手都会犯的一个错误,在业务层手工捕捉并处理了异常,你都把异常“吃”掉了,Spring自然不知道这里有错,更不会主动去回滚数据。
推荐做法:在业务层统一抛出异常,然后在控制层统一处理。

@Transactional
public int insertUser(User user) throws Exception
{
	// 新增用户信息
	int rows = userMapper.insertUser(user);
	// 新增用户岗位关联
	insertUserPost(user);
	// 新增用户与角色管理
	insertUserRole(user);
	// 模拟抛出SQLException异常
	boolean flag = true;
	if (flag)
	{
		throw new RuntimeException("发生异常了..");
	}
	return rows;
}

全局异常处理器

定义xx异常

public class CustomException extends RuntimeException{
    public CustomException(String message){
        super(message);
    }
}

全局异常统一处理 @ControllerAdvice
annotations 标识哪些控制器需要进行全局异常处理

@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalException {

    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandeler(SQLIntegrityConstraintViolationException ex){
        log.error(ex.getMessage());
        if(ex.getMessage().contains("Duplicate entry")){
            String[] s = ex.getMessage().split(" ");
            String name = s[2]+"已存在";
            return R.error(name);
        }
        return R.error("未知错误");
    }

    @ExceptionHandler(CustomException.class)
    public R<String> exceptionHandeler(CustomException ex){
        log.error(ex.getMessage());

        return R.error(ex.getMessage());
    }
}

使用

 public void remove(Long id){
        //查询当前分类是否关联了菜品,如果已经关联,抛出一个业务异常
        LambdaQueryWrapper<Dish> lambdaQueryWrapper=new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(Dish::getCategoryId,id);
        int count = dishService.count(lambdaQueryWrapper);
        if(count>0){
            //抛出异常
            throw new CustomException("当前分类下关联了菜品,不能删除");
		}	
}

数据校验使用

1.在controller上声明@Validated需要对数据进行校验。

public AjaxResult add(@Validated @RequestBody SysUser user)
{
    .....
}

2.然后在对应字段Get方法加上参数校验注解,如果不符合验证要求,则会以message的信息为准,返回给前端。

@Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
public String getNickName()
{
	return nickName;
}

@NotBlank(message = "用户账号不能为空")
@Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
public String getUserName()
{
	return userName;
}

@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
public String getEmail()
{
	return email;
}

@Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
public String getPhonenumber()
{
	return phonenumber;
}

也可以直接放在字段上面声明。

@Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
private String nickName;

自定义注解校验

使用原生的@Validated进行参数校验时,都是特定的注解去校验(例如字段长度、大小、不为空等),我们也可以用自定义的注解去进行校验,例如项目中的@Xss注解。

1、新增Xss注解,设置自定义校验器XssValidator.class

@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
@Constraint(validatedBy = { XssValidator.class })
public @interface Xss
{
    String message()

    default "不允许任何脚本运行";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

2、自定义Xss校验器,实现ConstraintValidator接口。

/**
 * 自定义xss校验注解实现
 * 
 * @author ruoyi
 */
public class XssValidator implements ConstraintValidator<Xss, String>
{
    private final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)
    {
        return !containsHtml(value);
    }

    public boolean containsHtml(String value)
    {
        Pattern pattern = Pattern.compile(HTML_PATTERN);
        Matcher matcher = pattern.matcher(value);
        return matcher.matches();
    }
}

3、实体类使用自定义的@Xss注解

@Xss(message = "登录账号不能包含脚本字符")
@NotBlank(message = "登录账号不能为空")
@Size(min = 0, max = 30, message = "登录账号长度不能超过30个字符")
public String getLoginName()
{
	return loginName;
}

自定义分组校验

有时候我们为了在使用实体类的情况下更好的区分出新增、修改和其他操作验证的不同,可以通过groups属性设置。使用方式如下

新增类接口,用于标识出不同的操作类型

public interface Add
{
}
public interface Edit
{
}

Controller.java

// 新增
public AjaxResult addSave(@Validated(Add.class) @RequestBody Xxxx xxxx)
{
    return success(xxxx);
}

// 编辑
public AjaxResult editSave(@Validated(Edit.class) @RequestBody Xxxx xxxx)
{
    return success(xxxx);
}

Model.java

// 仅在新增时验证
@NotNull(message = "不能为空", groups = {Add.class})
private String xxxx;

// 在新增和修改时验证
@NotBlank(message = "不能为空", groups = {Add.class, Edit.class})
private String xxxx;

提示

如果你有更多操作类型,也可以自定义类统一管理,使用方式就变成了Type.Add、Type.Edit、Type.Xxxx等。

package com.eva.core.constants;

/**
 * 操作类型
 */
public interface Type 
{
    interface Add {}

    interface Edit {}

    interface Xxxx {}
}

数据权限使用

部门数据权限注解

@DataScope(deptAlias = "d")
public List<...> select(...)
{
    return mapper.select(...);
}

部门及用户权限注解

@DataScope(deptAlias = "d", userAlias = "u")
public List<...> select(...)
{
    return mapper.select(...);
}

3、在mybatis查询底部标签添加数据范围过滤

<select id="select" parameterType="..." resultMap="...Result">
    <include refid="select...Vo"/>
    <!-- 数据范围过滤 -->
    ${params.dataScope}
</select>

例如:用户管理(未过滤数据权限的情况):

select u.user_id, u.dept_id, u.login_name, u.user_name, u.email
	, u.phonenumber, u.password, u.sex, u.avatar, u.salt
	, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by
	, u.create_time, u.remark, d.dept_name
from sys_user u
	left join sys_dept d on u.dept_id = d.dept_id
where u.del_flag = '0'

例如:用户管理(已过滤数据权限的情况):

select u.user_id, u.dept_id, u.login_name, u.user_name, u.email
	, u.phonenumber, u.password, u.sex, u.avatar, u.salt
	, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by
	, u.create_time, u.remark, d.dept_name
from sys_user u
	left join sys_dept d on u.dept_id = d.dept_id
where u.del_flag = '0'
	and u.dept_id in (
		select dept_id
		from sys_role_dept
		where role_id = 2
	)

结果很明显,我们多了如下语句。通过角色部门表(sys_role_dept)完成了数据权限过滤

and u.dept_id in (
	select dept_id
	from sys_role_dept
	where role_id = 2
)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值