삭제 기능 만들기
삭제 기능
삭제 기능을 구현하기 전 가장 고민했던 부분은 바로 insert 기능을 만들 때 api <고객> 테이블에 Count 되는 부분이었다 추가할 때 Count 값이 증가한다면 삭제할 때는 감소해야 하는데 처음에는 그냥 반대로 +1 이 아닌 -1 하면 되는 거 아닌가? 하고 진행했지만 insert 할 때는 입력창에 입력하는 api <고객>의 PK값이 있는데 삭제할 때는 그게 없으니 api <고객> 테이블에 Count를 찾을 수가 없었다
고민한 3가지 방법
1. 삭제할 때 insert처럼 고객 PK를 입력받기 <쉽게 해결하는 수단이지만… 이건 말이 안 된다>
2. 장치에 상태를 만들어 삭제가 아닌 상태를 변경하는 방향 <DB에 데이터가 계속 쌓이는 문제가 있다 실질적인 삭제가 아니기 때문에>
3. 삭제할 때 고객의 PK를 얻어온다 … < 가장 원하는 방법인데 좀처럼 방법이 생각이 안 남>
이걸 어떻게 처리할까를 한참을 고민하고 지금의 코드를 작성했습니다.
DeviceRepository
package com.apiservice.repository;
import com.apiservice.model.DeviceDTO;
import com.apiservice.model.DeviceVO;
import com.apiservice.model.ListDTO;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface DeviceRepository {
void deviceInsert(DeviceVO deviceVO);
void deviceDelete(Integer serviceNumber);
DeviceVO getPk(DeviceDTO deviceDTO); // device 테이블의 pk 와 member_number을 검사
}
- 삭제 기능의 deviceDelete
- Count 값의 변화를 위해 테이블을 한번 조회하는 getPk
DeviceRepository.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.apiservice.repository.DeviceRepository">
<insert id="deviceInsert">
insert into api.device( device_name, device_type, installer, in_date, region, member_number)
value(#{deviceName},#{deviceType},#{installer},now(),#{region},#{memberNumber})
</insert>
<delete id="deviceDelete">
delete
from api.device
where service_number = #{serviceNumber}
</delete>
<select id="getPk" resultType="com.apiservice.model.DeviceVO">
select service_number , member_number from api.device
where service_number = #{serviceNumber}
</select>
</mapper>
- getPk는 삭제할 때 유효성 검사와 apiRepository.deletDevicesCount 에서 memberNumber을 매칭 할 때 이용된다 (apiRepository.deletDevicesCount 는 아래에서 설계할 예정)
ApiRepository
package com.apiservice.repository;
import com.apiservice.model.ApiDTO;
import com.apiservice.model.ApiVO;
import com.apiservice.model.ListDTO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ApiRepository {
void insert(ApiDTO apiDTO);
void update(ApiDTO apiDTO);
void delete(Integer memberNumber);
List<ApiVO>selectList(ListDTO listDTO);
int getTotal(ListDTO listDTO);
ApiVO getPk(ApiDTO apiDTO); // api 테이블 pk
ApiVO getId(ApiDTO apiDTO); // api 테이블 memberId
void updateDevicesCount(@Param("memberNumber") Integer memberNumber, @Param("amount") int amount);
void deleteDevicesCount(@Param("memberNumber") Integer memberNumber);
}
- deleteDevicesCount는 device 삭제를 할때 Count 값의 감소를 위한 코드
ApiRepository.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.apiservice.repository.ApiRepository">
<sql id="search">
<where>
<if test="keyword != null">
<foreach collection="types" item="item" separator="OR" open="(" close=")">
<if test = 'item == "i"'>
member_id like concat('%',#{keyword} , '%')
</if>
<if test='item =="n"'>
member_name like concat('%' , #{keyword} , '%')
</if>
<if test='item =="p"'>
member_phone like concat('%' , #{keyword} , '%')
</if>
<if test='item =="a"'>
advert like concat('%' , #{keyword} , '%')
</if>
</foreach>
</if>
</where>
</sql>
<insert id="insert">
insert into api.api(member_id , member_pw , member_name , member_phone , advert)
values (#{memberId} , #{memberPw} , #{memberName} , #{memberPhone} , #{advert})
</insert>
<update id="update">
update api.api
set update_date = now()
<if test=" memberId != null and memberId != '' ">
, member_id = #{memberId}
</if>
<if test="memberPw != null and memberPw != '' ">
, member_pw = #{memberPw}
</if>
<if test="memberName != null and memberName != '' ">
, member_name = #{memberName}
</if>
<if test="memberPhone != null and memberPhone != '' ">
, member_phone = #{memberPhone}
</if>
<if test="advert != null and advert != '' ">
, advert = #{advert}
</if>
where member_number = #{memberNumber}
</update>
<delete id="delete">
delete
from api.api
where member_number = #{memberNumber}
</delete>
<select id="selectList" resultType="com.apiservice.model.ApiVO">
select member_number ,member_id , member_pw , member_name , member_phone , advert , update_date
from api.api
<include refid="search"></include>
order by member_number desc
limit #{skip},#{size}
</select>
<select id="getTotal" resultType="int">
select count (member_number) from api.api
<include refid="search"></include>
</select>
<select id="getPk" resultType="com.apiservice.model.ApiVO">
select member_number from api.api
where member_number = #{memberNumber}
</select>
<select id="getId" resultType="com.apiservice.model.ApiVO">
select member_id from api.api
where member_id = #{memberId}
</select>
<update id="updateDevicesCount">
update api.api set deviceCount = deviceCount + #{amount} where member_number = #{memberNumber}
</update>
<update id="deleteDevicesCount">
update api.api set deviceCount = deviceCount - 1 where member_number = #{memberNumber}
</update>
</mapper>
- deleteDevicesCount 는 쿼리가 실행될 때 Count 값에 -1을 해주고 memberNumber로 맵핑한다
DeviceService
package com.apiservice.service;
import com.apiservice.model.*;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public interface DeviceService {
void register(DeviceDTO deviceDTO , ApiDTO apiDTO);
void delete(Integer serviceNumber , DeviceDTO deviceDTO);
}
- Transactional 어노테이션을 걸어주자
DeviceServiceImpl
package com.apiservice.service;
import com.apiservice.controller.Handler.CustomException;
import com.apiservice.model.*;
import com.apiservice.model.Error.ErrorCode;
import com.apiservice.repository.ApiRepository;
import com.apiservice.repository.DeviceRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Log4j2
@RequiredArgsConstructor
public class DeviceServiceImpl implements DeviceService{
private final ApiRepository apiRepository;
private final DeviceRepository deviceRepository;
private final ModelMapper modelMapper;
@Override
public void register(DeviceDTO deviceDTO , ApiDTO apiDTO) {
DeviceVO deviceVO = modelMapper.map(deviceDTO, DeviceVO.class);
deviceRepository.deviceInsert(deviceVO);
//api<고객> 테이블 에 존재하는 PK 인지 확인
if(apiRepository.getPk(apiDTO) ==null){
log.info("ErrorCode NOT_INFO");
throw new CustomException(ErrorCode.NOT_INFO);
}
apiRepository.updateDevicesCount(deviceDTO.getMemberNumber(),1);
}
@Override
public void delete(Integer serviceNumber , DeviceDTO deviceDTO) {
//유효성 검사와 member_number을 매칭하기 위한 select
DeviceVO getPk = deviceRepository.getPk(deviceDTO);
//존재 안 하는 장치는 삭제할 수 없다
if(getPk == null){
throw new CustomException(ErrorCode.NOT_INFO);
}
log.info("deviceDelete");
deviceRepository.deviceDelete(serviceNumber);
apiRepository.deleteDevicesCount(getPk.getMemberNumber());
}
}
⭐가장 고민을 많이 한 부분이다 우선 getPK로 service_number , member_number 두 개를 확인하고 유효성 검사를 먼저 진행해준다 그리고 이제 삭제 로직이 실행되고 이후 api <고객> 테이블의 Count 값의 감소를 위한 apiRepository.deleteDevicesCount 가 실행된다 이때 맵핑하는 memberNumber을 getPk에서 받아온다 이렇게 하면 삭제되는 서비스가 어떤 고객에게 등록된 서비스인지 확인이 가능해진다.
DeviceController
package com.apiservice.controller;
import com.apiservice.model.ApiDTO;
import com.apiservice.model.DeviceDTO;
import com.apiservice.model.ListDTO;
import com.apiservice.model.ListResponseDTO;
import com.apiservice.service.DeviceService;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/device/")
@Log4j2
@RequiredArgsConstructor
public class DeviceController {
private final DeviceService deviceService;
@ApiOperation("Device Post register")
@PostMapping("/register")
public ResponseEntity registerPost(@Validated DeviceDTO deviceDTO){
log.info(deviceDTO);
log.info("controller register");
deviceService.register(deviceDTO , ApiDTO.builder()
.memberNumber(deviceDTO.getMemberNumber())
.build());
return new ResponseEntity(HttpStatus.OK);
}
@ApiOperation("Device post delete")
@PostMapping("/delete/{serviceNumber}")
public ResponseEntity delete(@PathVariable("serviceNumber") Integer serviceNumber , DeviceDTO deviceDTO){
log.info("-----------------------");
log.info("delete");
log.info("------------------");
deviceService.delete(serviceNumber , deviceDTO);
return new ResponseEntity(HttpStatus.OK);
}
}
- register 쪽 서비스 코드는 다음에 리뷰 하겠습니다!!
테스트를 해보자
현재 device <장치> 테이블
현재 api <고객> 테이블
10번 고객에게 1개의 장치가 등록되어있다 이걸 지워보자
swagger-ui 테스트
- 23번으로 등록된 장치를 삭제했다
삭제 후 device <장치> 테이블
삭제 후 api <고객> 테이블
계획한 대로 로직이 잘 동작하고 있는 걸 확인할 수 있다
'예제를 만들자 뚱땅뚱땅' 카테고리의 다른 글
API 만들기 연습 #11 (1) | 2022.09.06 |
---|---|
API 만들기 연습 #9 (0) | 2022.09.02 |
API 만들기 연습 #8 추가 설계 (0) | 2022.09.01 |
API 만들기 연습 #7 검색 (0) | 2022.08.31 |
API 만들기 연습 #6 유효성 검증 (0) | 2022.08.30 |