8. RestFulApi를 이용한 프로젝트만들기, war packaging (demo)

8. RestFulApi를 이용한 프로젝트만들기, war packaging (demo)

extends SpringBootServletInitializer​

CRUD(DB) HttpMethod URL SELECTALL GET Http://localhost:8080/members SELECTONE GET Http://localhost:8080/members/jimin INSERT POST Http://localhost:8080/members UPDATE PUT Http://localhost:8080/members/jimin DELETE DELETE Http://localhost:8080/members/jimin

브라우저에서는 PUT과 DELETE를 사용하지 못하기 때문에 PostMan을 이용하여 테스트를 할 수 있다.

GET방식과 Post방식,Put, DELETE가 같은 URL이 같더라도 httpmethod에 따라 실제로 작동해야될 CRUD가 달라진다.

text같은 것들도 물론 사용이 가능하지만 검색, 삭제, 치환이 가능하기때문에 xml을 사용한다.

하지만 parsing이 어렵다는 이유로 json형식으로 데이터를 오고가게하는 방법을 선호하기 시작했다. Restfulapi(RestFul 스펙에 의해서 만들어진 Api)를 json형태로 데이터를 보내고 받을 예정이다.

Jar로 페키징되어있다면 RestFulApi를 사용하지 못하기 때문에 War로 리패키징하여 Tomcat에 올려 Restcontroll로 바꾼다.

War를 이용하여 프로젝트 만들기

<Spring Initailizr>

Sts를 이용하여 프로젝를 만들어도 되지만 dependency가 안되는 것들(특히 lombok때문)도 있기때문에 Spring Initailizr를 이용하여 만들도록 하였다.

Dependency 설명 SpringBootDevTools 저장시 자동으로 서버를 재시작해줌 Lombok setter,getter등 여러가지 Annotaion을 사용할 수 있게해줌 SpringConfiguration Processor ApplicationProperties외에 추가 환경을 할 경우 연결해줌 SpringWeb Web을 사용시 필요(RestFul) JDBC Api Mybatis를 사용하더라고 DB를 사용하려면 필요함 MyBatis FrameWork Mybatis사용시 필요 MySql Driver DB사용시에 필요

Log4jdbc를 사용하기 위한 Dependency 추가

org.bgee.log4jdbc-log4j2 log4jdbc-log4j2-jdbc4.1 1.16

logBack.xml 생성

DEBUG로 level을 낮추어 어떤 순서로 실행되는지 알 수 있다

log4jdbc.log4j2파일 생성

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator #Disable - Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. #The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary. # log4jdbc의 드라이브 클래스 설정 log4jdbc.drivers=com.mysql.cj.jdbc.Driver log4jdbc.auto.load.popular.drivers=false

spy가 자꾸 예전 드라이버를 찾기때문에 CJ이가 붙은 드라이버를 따로 명시해준다.

db에서 데이터가 넘어오는 순서

RDBMS -> JDBC Driver -> Data Source(hikari) -> jdbc interface(mybatis) -> Dao -> service -> controller

ERD생성

<ERD>

체크제약조건

체크제약조건 CK_Member_gender gender IN('1','0') CK_Member_city city IN('서울','부산','대구','광주,'대전','안천') CK_Member_age age BETWEEN 1 AND 60

모델 영역에서 스키마 이름을 내가 사용할 DB이름으로 바꾸고 포워드 엔지니어링을 진행한다.

DBConnection Explorer에 가서 new를 누르고 MysqlConnecttor.jar를 이용하여 사용가능하도록 한다.

DataBaseConfig생성

@Configuration @PropertySource("classpath:/application.properties") @Slf4j public class DatabaseConfiguration { @Autowired private ApplicationContext applicationContext; @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari") public HikariConfig hikariConfig() { return new HikariConfig(); } @Bean public DataSource dataSource() throws Exception { DataSource dataSource = new HikariDataSource(hikariConfig()); log.info("datasource : {}", dataSource); return dataSource; } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception{ SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean(); sqlSessionFactory.setDataSource(dataSource); Resource configLocation = new PathMatchingResourcePatternResolver().getResource("classpath:/mapper/mybatis-config.xml"); sqlSessionFactory.setMapperLocations(applicationContext.getResources("classpath:/mapper/mybatis-mapper.xml")); sqlSessionFactory.setConfigLocation(configLocation); return sqlSessionFactory.getObject(); } @Bean public SqlSessionTemplate sqlSessioinTemplate(SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }

DataSource를 연결하기위한 환경설정 Class를 생성한다.

DemoApplocation.java에서 설정바꾸기

@SpringBootApplication @ComponentScan(basePackages = {"com.example"}) public class DemoApplication extends SpringBootServletInitializer{ public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(DemoApplication.class); } }

main method가 있는 곳 뿐만아니라 com.example아래에 있는 곳을 스캔할 수 있도록 ComponentScan을 com.example로 바꾸어준다.

DataBaseConfiguration을 연결해주기위한 클래스 생성

@Configuration @PropertySource("classpath:/application.properties") @Slf4j public class DatabaseConfiguration { @Autowired private ApplicationContext applicationContext; @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari") public HikariConfig hikariConfig() { return new HikariConfig(); } @Bean public DataSource dataSource() throws Exception{ DataSource dataSource = new HikariDataSource(hikariConfig()); return dataSource; } }

HikariCP를 연결해주기위한 설정을 한후 junit에서 DataSource가 null인지 테스트를 한다

MemberVO생성

@Data @NoArgsConstructor @AllArgsConstructor public class MemberVO { private String userid; private String passwd; private String name; private int age; private String gender; private String city; }

MemberDao interface 생성

public interface MemberDao { void create(MemberVO member); void readAll(Map map); void read(Map map); void update(MemberVO member); void delete(String userid); }

파라미터가 많을수록 map을 사용하는 것이 좋다. 하지만 이번에는 쉽게 select할 경우에만 map을 사용할 것이다.

리턴타입은 모두 Map안에서 해결할 수 있기때문에 리턴타입은 모두 void이다

maybatis-mapper.xml 생성

{ call sp_member_select_all() } { call sp_member_select(?) } { call sp_member_insert(?,?,?,?,?,?) }

id는 기본키를 명시해준것임으로 result를 사용하여도 상관없다

스토드프로지저를 사용할 것이기 때문에 statementType은 CALLABEL을 사용하였고

MemberDao interface를 상속받는 MemberDaoImpl클래스 생성

@Repository("memberDao") public class MemberDaoImpe implements MemberDao { @Autowired private SqlSession sqlSession; @Override public void create(MemberVO member) { this.sqlSession.insert("Member.insert", member); } @Override public void readAll(Map map) { System.out.println("ddd"); List list = this.sqlSession.selectList("selectAll"); map.put("results", list); } @Override public void read(Map map) { MemberVO member = this.sqlSession.selectOne("Member.selectOne", (String)map.get("userid")); map.put("result", member); } @Override public void update(MemberVO member) { } @Override public void delete(String userid) { this.sqlSession.delete("Member.delete", userid); } }

MemberService interface생성

public interface MemberService { void insertMember(MemberVO member); void selectAllMembers(Map map); void selectMember(Map map); void updateMember(MemberVO member); void deleteMember(String userid); }

MemberService interface를 상속받는 MemberService Impl생성

package com.example.service; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.dao.MemberDao; import com.example.vo.MemberVO; @Service("memberService") public class MemberServiceImpl implements MemberService { @Autowired private MemberDao memberDao; @Override public void insertMember(MemberVO member) { // TODO Auto-generated method stub } @Override public void selectAllMembers(Map map) { this.memberDao.readAll(map); } @Override public void selectMember(Map map) { this.memberDao.read(map); } @Override public void updateMember(MemberVO member) { this.memberDao.create(member); } @Override public void deleteMember(String userid) { this.memberDao.delete(userid); } }

MemberController생성

RestController를 이용하기

@RestController @Slf4j public class MemberController { @Autowired private MemberService memberService; @GetMapping("/members") public Map list(Model model) { Map map = new HashMap(); this.memberService.selectAllMembers(map); List list = (List)map.get("results"); return map; //templates/list.html } @GetMapping("/members/{userid}") public Map display(@PathVariable String userid) { Map map = new HashMap(); map.put("userid",userid); this.memberService.selectMember(map); MemberVO member = (MemberVO)map.get("result"); map.remove("userid"); return map; } @PostMapping("/members") public Map insert(@RequestBody MemberVO member) { Map map = new HashMap(); this.memberService.insertMember(member); map.put("code", "success"); return map; } @DeleteMapping("/members/{userid}") public Map delete(@PathVariable String userid) { Map map = new HashMap(); this.memberService.deleteMember(userid); return map; } }

리턴은 map으로 하면 알아서 json화 하여 데이터를 보내준다.

Spring legacy였다면 젝슨 바인드라는 모듈이 필요하지만 이미 내장이 되어 있기 때문에 따로 사용하지 않아도 된다

model이 필요없는 이유는 전부 json을 이용하여 보내줄 것이기 때문이며

json형태로 보내줄것이기 때문에 리턴타입은 반드시 Map으로 지정한다.

설명 @PathVariable {userid}에 따라 원하는 값을 받고싶을 때 사용하는 어노테이션

Mapper-configClass생성

resultMap에서 길게 com.example.vo라고 쓰지않고 memberVO라고 별칭으로 사용할 수 있게 alias를 설정해준다.

War사용하기

war

version과 name사이에 적어준다

Tomcat라이브러리 가져오기

org.springframework.boot spring-boot-starter-tomcat 2.6.1

main method가 있는 곳으로 가기

@SpringBootApplication @ComponentScan(basePackages = {"com.example"}) public class DemoApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override protected SpringApplicationBuilder createSpringApplicationBuilder() { return new SpringApplicationBuilder(DemoApplication.class); } }

전부 다 한후에 maven istall을 한다.

servers에 들어가 진짜 톰켓을 붙여준다(ver9)

from http://wonho.tistory.com/18 by ccl(A) rewrite - 2021-12-09 00:28:01