Как реализовать SecurityContextHolder в универсальной базовой службе, придерживаясь принципов SOLID?JAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Как реализовать SecurityContextHolder в универсальной базовой службе, придерживаясь принципов SOLID?

Сообщение Anonymous »

У меня есть абстрактная базовая служба, включающая базовые операции CRUD. Однако может возникнуть ситуация, когда, например, при сохранении объекта «Сообщение» мне также необходимо сохранить информацию о пользователе, создавшем сообщение, поскольку сообщение и пользователь являются связанными объектами.
Тогда Я подумал, что было бы разумнее получить информацию о пользователе из SecurityContextHolder и сохранить ее. Однако я не уверен, как применить это к методу сохранения в базовой службе для операций CRUD. В некоторых операциях по сохранению сущностей мне не нужно иметь дело с информацией о пользователе, поэтому проблем с ее сохранением не возникает. Но для сохранения сообщения я хочу получить пользователя из SecurityContextHolder вместо того, чтобы получать его из requestDto.
Как я могу добиться этого, не нарушая базовую структуру, избегая повторения кода и придерживаясь принципам SOLID так, как это удобно для корпоративного проекта?

Код: Выделить всё

@RequiredArgsConstructor
public abstract class BaseServiceImpl<
Entity extends BaseEntity,
DTO extends BaseDTO,
RequestDTO,
Mapper extends IBaseMapper,
Repository extends BaseRepository>
implements BaseService {

private final Mapper getMapper;

private final Repository getRepository;

@Transactional
public DTO save(RequestDTO requestDTO) {
Entity entity = getMapper.requestDTOToEntity(requestDTO);
getRepository.save(entity);
return getMapper.entityToDTO(entity);
}

public List getAll() {
return getMapper.entityListToDTOList(getRepository.findAll());
}

public DTO update(UUID uuid, RequestDTO requestDTO) {
Entity entity = getRepository.findByUuid(uuid).orElse(null);
if (entity != null) {
entity = getMapper.requestDtoToExistEntity(entity, requestDTO);
getRepository.save(entity);
return getMapper.entityToDTO(entity);
} else {
return null;
}
}

public DTO getByUUID(UUID uuid) {
Entity entity = getRepository.findByUuid(uuid).orElse(null);
if (entity != null) {
return getMapper.entityToDTO(entity);
} else {
return null;
}
}

@Transactional
public Boolean deleteByUUID(UUID uuid) {
Entity entity = getRepository.findByUuid(uuid).orElse(null);
if (entity != null) {
getRepository.delete(entity);
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}}
Интерфейс базового сервиса

Код: Выделить всё

public interface BaseService<
DTO extends BaseDTO,
RequestDTO> {

DTO save(RequestDTO requestDTO);

List getAll();

DTO update(UUID uuid, RequestDTO requestDTO);

DTO getByUUID(UUID uuid);

Boolean deleteByUUID(UUID uuid);
}
Служба PostServiceImpl

Код: Выделить всё

public class PostServiceImpl extends BaseServiceImpl<
PostEntity,
PostResponseDTO,
PostRequestDTO,
PostMapper,
PostRepository>
implements PostService {
// Other codes...
}
Интерфейс почтового сервиса

Код: Выделить всё

public interface PostService extends BaseService
 {
//Other codes...
}
Когда я спросил ИИ ChatGPT, он предложил мне два решения, и я тоже хотел бы ими поделиться.
Решение 1:

Код: Выделить всё

@RequiredArgsConstructor
public abstract class BaseServiceImpl<
Entity extends BaseEntity,
DTO extends BaseDTO,
RequestDTO,
Mapper extends IBaseMapper,
Repository extends BaseRepository>
implements BaseService {

//Other codes...

protected void customizeBeforeSave(Entity entity, RequestDTO requestDTO) {
// Varsayılan olarak hiçbir işlem yapılmaz.
}
}

@Service
public class PostServiceImpl extends BaseServiceImpl<
PostEntity,
PostResponseDTO,
PostRequestDTO,
PostMapper,
PostRepository> {

private final UserContextService userContextService;

public PostServiceImpl(PostMapper mapper, PostRepository repository,
UserContextService userContextService) {
super(mapper, repository);
this.userContextService = userContextService;
}

@Override
protected void customizeBeforeSave(PostEntity entity, PostRequestDTO requestDTO) {
UserEntity currentUser = userContextService.getCurrentAuthenticatedUser();
entity.setAuthor(currentUser); // Kullanıcıyı `author` olarak ata
}
}
Решение 2:

Код: Выделить всё

@Mapper(componentModel = "spring")
public interface PostMapper extends IBaseMapper
PostRequestDTO>  {

@Mapping(target = "author", expression = "java(getAuthenticatedUser())")
PostEntity requestDTOToEntity(PostRequestDTO dto);

default UserEntity getAuthenticatedUser() {
return (UserEntity) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
Решение 3:

Код: Выделить всё

@Aspect
@Component
public class SecurityAspect {

@Pointcut("execution(* com.example.service.BaseServiceImpl.save(..)) && args(requestDTO)")
public void saveMethod(Object requestDTO) {}

@Before("saveMethod(requestDTO)")
public void setUserFromSecurityContext(Object requestDTO) {
if (requestDTO instanceof PostRequestDTO) {
UserEntity currentUser = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
((PostRequestDTO) requestDTO).setAuthorId(currentUser.getId());
}
}
}
Это мой личный проект, и я стремлюсь следовать принципам SOLID, не повторяя код. Я пытаюсь изучить и внедрить наиболее подходящий подход, используемый в корпоративных проектах. Буду признателен за вашу помощь.

Подробнее здесь: https://stackoverflow.com/questions/792 ... ile-adheri
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»