• 각 라우터에서 처리해야하는 함수 코드가 길면 유지보수가 어려우니
  • 라우트에서 처리하는 함수들만 모아서 컨트롤러(controller)를 만들자
# yarn add koa-bodyparser

src/api/posts/posts.ctrl.js

let postId = 1; // init

// posts data

const posts = [
  {
    id: 1,
    title: '제목',
    body: '내용',
  },
];

/* 포스트 작성
POST /api/posts
{ title, body }
*/
exports.write = ctx => {
  const { title, body } = ctx.request.body;
  postId += 1;
  const post = { id: postId, title, body };
  posts.push(post);
  ctx.body = post;
};

/* 포스트 목록 조회
GET /api/posts
*/
exports.list = ctx => {
  ctx.body = posts;
};

/* 특정 포스트 조회
GET /api/posts/:id
*/

exports.read = ctx => {
  const { id } = ctx.params; // default datatype: string
  const post = posts.find(p => p.id.toString() === id);
  if (!post) {
    ctx.status = 404;
    ctx.body = {
      message: '포스트가 존재하지 않습니다',
    };
    return;
  }
  ctx.body = post;
};

/* 특정 포스트 제거
DELETE /api/posts/:id
*/
exports.remove = ctx => {
  const { id } = ctx.params;
  const index = posts.findIndex(p => p.id.toString() === id);

  if (index === -1) {
    ctx.status = 404;
    ctx.body = {
      message: '포스트가 존재하지 않습니다',
    };
    return;
  }
  posts.splice(index, 1);
  ctx.status = 204; // No Content
};

/* 포스트 수정 (교체)
PUT /api/posts/:id
{ title, body }
*/
exports.replace = ctx => {
  const { id } = ctx.params;
  const index = posts.findIndex(p => p.id.toString() === id);
  if (index === -1) {
    ctx.status = 404;
    ctx.body = {
      message: '포스트가 존재하지 않습니다',
    };
    return;
  }
  posts[index] = {
    id,
    ...ctx.request.body,
  };
  ctx.body = posts[index];
};

/* 포스트 수정 (특정 필드 변경)
PATCH /api/posts/:id
{ title, body }
*/
exports.update = ctx => {
  const { id } = ctx.params;
  const index = posts.findIndex(p => p.id.toString() === id);
  if (index === -1) {
    ctx.status = 404;
    ctx.body = {
      message: '포스트가 존재하지 않습니다',
    };
    return;
  }
  posts[index] = {
    ...posts[index],
    ...ctx.request.body,
  };
  ctx.body = posts[index];
};

src/api/posts/index.js

const Router = require('koa-router');
const postsCtrl = require('./posts.ctrl');

const posts = new Router(); 

posts.get('/', postsCtrl.list);
posts.post('/', postsCtrl.write);
posts.get('/:id', postsCtrl.read);
posts.delete('/:id', postsCtrl.remove);
posts.put('/:id', postsCtrl.replace);
posts.patch('/:id', postsCtrl.update);

module.exports = posts; 

spring boot AOP 구현하기.
Aop를 잘 모르지만

  • Http 요청이 왔을때 끼어들어 요청에 대한 권한이 있는지 체크하기 위한 AOP를 개발하려한다.
    : http요청이 왔을때 실제 응답을 주기전에 권한을 체크하고 권한이 있으면 계속 진행하도록 해주고, 권한이 없으면 진행을 막는다.
  • 더불어 특정 controller에는 권한체크를 하지 않고, http request로 온 header안에 정보를 parameter로 전달하려한다.
  1. pom.xml
    <dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
  1. AopConfig.java
    @Around 이노테이션으로 requestMapping으로 들어오는 요청에 대해서 AOP를 적용할것임을 명시.
    특정 controller 접근시에는 parameter를 넘겨주도록했음.
    주석 참고.
@Configuration
@Aspect
@EnableAspectJAutoProxy() 
public class AopConfig { 
    ...
    @Around("@annotation(requestMapping)") 
    public final Object checkPermission(final ProceedingJoinPoint pjp
                                      , final RequestMapping requestMapping){
        .... 
        //권한을 체크하는 함수에서 true값을 return해주면 계속해서 진행 
        if (permission.check(pjp, requestMapping, httpServletRequest)) { 
            return pjp.proceed();
        } 

        ....
        String email = .... ;
        //특정 controller접근시에는 권한체크는 하지 않고 파라미터만 전달하여 계속 진행
        if (pjp.getSignature().toString().contains("com.xxx.xxx.controller.xxx")) {
            return pjp.proceed(new Object\[\]{email});
        } 
        ... 


        //권한 없는 경우 null을 return하여 계속해서 진행할 수 없음. 
        return null; 
        } 
 }

참고.
proceedjointpoint로 parameter를 넘겨줄때는 넘겨준 parameter와 동일한 명칭, 순서로 받아야한다.

@ResponseBody 
@RequestMapping(method = RequestMethod.GET, value = "/user") 
public LoginUser getLoginEmail(final String email) { 
    LoginUser loginUser = new LoginUser(); 
    loginUser.setEmail(email);
    return loginUser;
}

+ Recent posts