@RequestMapping 
 핸들러 매핑과 핸들러 어댑터의 대상이 오브젝트가 아니라 메소드이다. 
 Controller와 같이 하나의 메소드를 가진 인터페이스로 정의되는 컨트롤러는 기본적으로 URL 당 하나의 컨트롤러 오브젝트가 매핑되고 컨트로러당 하나의 메소드만 DIspatcherServlet의 호출을 받을수 있다.
 >>어노테이션은 부여되는 대상의 타입이나 코드에는 영향을 주지 않는 메타정보이다. 

@MVC의 핸들러 매핑을 위해서는 DefaultAnnotationHandlerMapping이 필요하다. 매핑정보로 @RequestMapping 어노테이션을 사용한다.  메소드, 타입 레벨에 다 붙으며 이 정보를 결합하여 최종 매핑 정보를 생성한다. 한 클래스에 같이 사용하면 타입레벨속에 메소드 레벨이 포함된다. 

1.@RequestMappping 
-String[ ] value() : URL 패턴
-RequestMethod[ ] method() : http 요청메서드 , ex) @RequestMapping(  "/hello/add", method=RequestMethod.GET ) @RequestMapping(  "/hello/add", method=RequestMethod.POST) 
폼 처리할'대 동일한 URL에 대해 GET과 POST 처리시 용이 
-Stringp[] : 같은 URL을 사용하더라도 HTTP 요청 파라미터에 따라 별도의 작업을 해주고 싶을떄, ex) @RequestMapping(  value= "/hello/edit", params="type=admin" ) 
-String[ ] headers(): HTTP해더, 저장방식이 params와 비슷하게 해더이름=값의 형식을 사용한 경우
ex) @RequestMapping(  value="/hello", headers="content-type=text/*" ) 

메소드 레벨의 매핑조건이 공통점이 없는 경우라면 타입레벨에서 주지 않고 메소드 레벨에 독립적으로 매핑정보를 지정할수있다. 이때 타입레벨에서는 @ReqeustMapping을 꼭 부여해주어야 한다.  이떄 @Controller 어노테이션을 붙여 빈 자동스캔방식으로 등록되게 했다면 생략 가능하다. 

>>핸들러 매핑은 원래 핸들러 오브젝트를 결정하는 전략이다. 어노테이션이 영향으로 매핑 방법이 메소드 레벨까지 세분화 되기는 했지만 타입 컨트롤러와의 일관성을 위해 어노테이션 방식의 핸들러 매핑에서도 일단 오브젝트까지만 매핑을 하고 최종 실행할 메소드는 핸들러 어댑터가 결정한다. 

@RequestMapping( "/user/*")
public class UserController{
    @RequestMapping publid void add() {
    }
}
클래스 레벨에서는 /*로 끝나게 하고 메소드 레벨에서는 @RequestMapping만 부여해주면 매소드이름이 URL이 된다. 

상속도 가능하다.
super클래스에서 클래스 레벨로 @RequestMapping( "/user") 해놓았다면 sub클래스의 메소드 레벨의 
@RequesMapping("/list") public String list() {...} 로 호출가능하다. 


@Controller
DefaultAnnotationHandlerMapping은 사용자 요청을 @RequestMapping정보를 활용해서 컨트롤러 빈의 메소드에 매핑해준다. 그리고 AnnotationMethodHandlerAdpter는 매핑된 메소드를 실제로 호출하는 역활을 담당한다. 

 메소드 파라미터의 종류 
-httpServletRequest , httpServletResponse
-패스변수 
url: /user/view/10 
@RequestMapping( "/user/view/{id}" )
public String view( @PathVariable("id") int id ) {

}
@RequestParam
http 요청 파라미터를 메소드 파라미터에 넣어준다. 
Map<String, String>타입으로 선언하면 모든 요청파라미터를 담을 맵으로 받을 수 있다. 

@RequestHeader

@ModelAttribute 
파라미터타입으로 오브젝트를 만들고 프로퍼티를 토해 요청파라미터를 넣어준다. 
생략가능하며 @RequestParam,@ModelAttribute 생략되었을 경우 string, int는 전자로 보고 그 외 복잡한 오브젝트는 후자로 알아서 본다.

@RequestBody 
http 요청의 본문이 그대로 전달된다. 
xml이나 json기반의 메세지를 사용하는 요청의 경우 매우 유용하다. 
AnnotationMethodHandlerAdapter에는 HttpMessageConverter 타입의 메세지 변환기가 여러개 등록되어있다. 이 어노테이션이 있으면 http요청의 미디어 타입과 파라미터 타입을 먼저 확이한다. 메시지 변환기 중에서 해당 미디어 타입과 파라미터 타입을 처리할수있는것이 있으면 http 요청이 본문부분을 통째로 변환해서 지정된 메소드 파라미터로 전달해준다. 

>>AnnotationMethodHandlerAdapter가 호출하는 컨트롤러 메소드의 사용 가능한 파라미터타입과 어노테이션이다. 


리턴타입의 종류
컨트롤러가 DIspatchServlet에 돌려줘야하는 정보는 모델과 뷰다. 핸들러 어댑터를 거쳐서 최종적으로 DIspatcherServlet에 돌아갈때는 ModelAndView 타입으로 리턴값이 전달된다. httpServletRsponse에 직접 결과를 넣어 리턴한는 경우도 있다. 
-@ModelAttribute  모델  오브젝트 또는 커맨드 오브젝트 : 모델 오브젝트의 이름은 파라미터 타입 이름을 따른다. 
-Map. Model ModelMap 파라미터 : 뷰에 전달되는 모델에 자동으로 추가
-@ModelAttribute 메소드

모델의 바인딩과 검증
 컨트로러 메소드에 @modelAttribute가 지정된 파라미터를 @controller 메소드에 추가하면 크게 세 가지 작업이 자동으로 진행된다. '
 -파라미터 타입의 오브젝트를 만든다. 
 -준비된 모델 오브젝트의 프로퍼티에 웹 파라미터를 바인딩해준다.  http를 통해 전달되는 파라미터는 기본적으로 문자열인데 프로퍼티가 스트링이 아니라면 적절한 타입으로 변환해준다. 
 
 -모델의 값을 검증한다. 

 ing 1200p


출저 : 토비의 스프링







 



'STUDY > SPRING' 카테고리의 다른 글

Java EE 디자인패턴(ing)  (0) 2018.11.12
DATA Access  (0) 2018.11.08
Aspect Oriented Programming  (0) 2018.11.06
TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02

 
개념정리용 도서로 2018.11.12 - 2018.11.15

자바 EE

자바 EE 어플리케이션
-메타 데이터를 어노테이션을 달아놓은 POJO만 있으면 EJB(상태성/무상태성), servlet, jsf기반 빈(backig bean), 퍼시스턴스 개체, 싱글톤, REST 웹 서비스를 만들 수 있다. 

-다중 티어 아키텍쳐이다
클라이언트 티어, 미들 티어( 웹 레이어 + 비즈니스 레이어 ), 엔터프라이즈 정보 시스템 티어로 나뉜다. 
클라이언트 티어(프리젠테이션 티어):  클라이언트 - 서버 구저에서 클라이언트에 해당하는 애플리케이션 전부를 일컫는다. 
미들티어: 웹 컨테이너와 EJB컨테이너를 제공한다. 웹 레이어 기술은자바 서버 페이지(JSP), 표현식 언어(EL), 자바 서버페이지(JSTL)가 클라이언트로 보낼 응답을 포장하는 동안 서블릿은 웹 흐름을 제어하고 교통정리를 한다.  비즈니스 레이어는 업무 요건을 처리하거나 도메인 내부의 특정 비즈니스 로직을 실행한다. 비즈니스 레이어는 자바 퍼시스턴스(JPA), 자바 트랜잭션(JTA), 자바 데이터베이스 연결(JDBC) 기술이있다. 
EIS티어 :  DB형태의 데이터 저장 단위로 구성하지만 데이터를 공급하는 리소스면 어느것이든 가능



패턴은 세가지 유형으로 나눈다. 

생성패턴( Createional pattern ) - 객체의 생성, 초기화, 클래스 선택에 관한 패턴 ( 싱글턴 , 팩토리 )
행동패턴( Behavioral pattern ) - 객체간 소통, 메시징, 상호작용에 관한 패턴 ( 옵져버 )
구조패턴( structural pattern ) - 클래스와 객체 관계를 조직하는 패턴 ( 데코레이션 )

1.퍼사드 패턴
 복잡한 비즈니스 로직을 상위 레벨의 인터페이스로 캡슐화해서 하위 시스템에 더 쉽게 접근하능하도록 할수있게 한다. 

2.싱글톤 패턴
3.의존체 주입과 CDI
4.팩토리 패턴
5.장식자 패턴
6.AOP
7.비동기
8.타이머 서비스
9.옵저버
10.데이터 접근 패턴
11.REST형 웹서비스
12.mvc
13.나머지 자바 EE패턴











'STUDY > SPRING' 카테고리의 다른 글

@MVC (ing)  (0) 2018.11.12
DATA Access  (0) 2018.11.08
Aspect Oriented Programming  (0) 2018.11.06
TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02

스프링은 주요 데어터 엑서스기술인 자체적인 dataSource 생성 방식 대신 스프링 빈으로 등록돤 DataSource를 사용하여 필요한 방법을 제공해준다. 


스프링의 JDBC 기술과 동작원리
JDBC : 자바의 데이터 엑서스 기술이 기본이 되는 로우레벨의 API이다. 
기술
1.Connection 열기와 닫기
2.Statement 준비와 닫기 및 실행
sql 정보가 담긴 statement 또는 preparedStatment를 생성하고 필요한 준비작업을 한다. 
3.ResultSet 루프
ResultSet에 담기 쿼리 실행 결과가 한건 이상이라면 루프를 돌면서 각자 로우를 처리해줘야하는데 루프름 만들어 반복해주는것도 스프링 JDBC가 해주는 작업이다. 
4.예외처리의 반환
5.트랜잭션 처리 

SimleJdbcTemplate
 jdbcTemplate과 NameParameterJdbcTemplate에서 가장 많이 사용되는 기능을 통합하고 자바 5이상의 장점을 최대한 활용할 수 있게 만든것이다. 
멀티 스레드 환경에서도 안전하게 공유해서 사용가능하다. 

SimpleJdbcInsert, SimpleJdbcCall
DB가 제공해주는 메타정보를 활용해서 최소한의 코드만으로 단순한 JDBC코드를 작성하게 해준다.

sql파라미터
작업시 문자열로 된 sql을 제공해줘야하는데 파라미터 바인딩 방법을 사용한다. 
map / mapSQLParameterSource 사용
 -실행메소드 INSERT, UPDATE, DELETE와 같은 SQL을 사용할때 simpleJdbcTemplete의 update()를사용
 -조회메소드 
 -배치메소드 update()로 실행하는 sql들을 배치모드로 실행하게 해준다 JDBC statement를 사용하여 addBatch(), executeBatch() 메소드르 이용해 여러개의 sql을 처리한다. 

스프링의 DAO
 보통 DAO는 도메인 오브젝트 또는 DB 데이틀 단위로 만든다 . 스프링은 JdbcDaoSupport라는 JDBC를 이용한 DAO작서에 사용할수있는 추상클래스를 제공하고 있다. 

MYbatis 

 자바 오브젝트와 sql문 사이의 자동매핑 기능을 지원하는 ORM 프레임워크이다. 
sql을 자바 코드에서 분리하여 별도의 xml 파일 안에 작성하고 관리할 수 있어 sql 변경시 자바코드를 수정하고 컴파일 하지 않아도 된다.

 ORM(Object Relation Mapping) : 오브젝트와 RDB 사이에 존재하는 개념과 접근방법, 성격차이 때문에 요구되는 불편한 작업을 제거해줘서 개발자가 오브젝트를 가지고 정보를 다루면 ORM 프레임워크가 이를 RDB에 적절한 형태롸 변환해주거나 그 반대로 RDB에 저장되어있는 정보를 자바 오브젝트가 다루기 쉬운 형태로 변환해주는 기술이다. 
 따라서 ORM을 사용하는 개발자는 모든 데이터를 오브젝트 관점으로 본다. 

iBatis -> MyBatis
 -Apache project 팀에서 google code팀으로 이동하면서 명칭수정
 -용어변경
 SqlMapConfig -> Configration
 sqlMap => Mapper
 resultClass -> resultType
-자바 1.4까지만 iBatis 사용
-lib제공
<dependency>
    <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.2.2</version>
</dependency>
 
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
    <version>1.2.0</version>
</dependency>
-sqlMapClient DI 설정불필요 , sqlsessionFactory, sqlSessionTemplate만 bean id 지정하면 됨 ...


등록, 수정 , 삭제
 insert()  
 sql아이디(statementName)와 파라미터 오브젝트를 넣어주면 해당 insert 문을 실행한다. 
내부적으로 ibatis의 SqlMapExecutor의 insert() 메소드가 사용된다. 파라미터 유무에 따라 다음 두가지중 하나가 사용된다.
  Object insert( String statementName )
  Object insert( String statementName, Object parameterObject )

 update()
 실행후 영향받은 로우개수를 리턴해주는 메서드 2개와 로우 개수를 체크해주는 메소드 1개가 있다. 기대했던 로우수와 다른 경우 예외가 발생한다. 

 delete() 
  실행후 영향받은 로우개수를 리턴해주는 메서드 2개와 로우 개수를 체크해주는 메소드 1개가 있다. 기대했던 로우수와 다른 경우 예외가 발생한다. 

 조회
 단일 로우 오브젝트: 실행 결과가 한건
 다중 로우: 실행결과가 한건 이상인 경우 각 로우를 오브젝트에 담아 이를 다시 리스트로 돌려준다.
 다중 로우 조회( queryForMap() ): 맵이 앤드리마다 로우 하나의 내용이 들어간다. 맵의 키는 지정된 컬럼값이 사용된다. 
 핸들러 방식 ( queryWithRowHandler() ): sql의 결과를 루프를 돌면서 각 로우마다 콜벡 오브젝트를 호출하는 방식이다. 

mybatis 사용예시
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
        p:dataSource-ref="dataSource"
        p:configLocation="classpath:sqls/mybatis-config.xml"
        p:mapperLocations="classpath*:sqls/**/sql-*.xml">
    </bean>
    mybatis-config.xml
    <configuration>
        <typeAliases>
             <typeAlias alias="MemberVO"                type="com.bo.common.vo.MemberVO"/>
             <typeAlias alias="BoardVO"                 type="com.bo.common.vo.BoardVO"/>
        </typeAliases>
    <configuration>


    @VO( "MemberVO" )
    public class MemberVO{
       
       @Name( "순번" )
       private Object      seq;
       @Name( "순번필드명" )
       private String      seqName;
       @Name( "대상테이블명" )
       private String      tblName.... 
    member.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="memberInfo">
       <resultMap type="MemberVO" id="result" />
       <select id="listMember" resultMap="result" parameterType="java.util.HashMap">
            SELECT * FROM tbl_member WHERE memberTeam=#{where.memberTeam}
        </select>.....
   
   MemberDaoImpl
      @Repository( "MemberDaoImpl" )
   public class MemberDaoImpl implements MemberDao{
       @Autowired
       @Resource ( name = "commonDB" )
       private SqlSession  sqlSession;
       @Override
       public List<MemverVO> list( Object object ) throws Exception{
             return sqlSession.selectList( "memberInfo.listMember", object );
       } ....
그밖의  mybatis 동적 SQL

    1.<trim>, <if>
    <select id="CommonFileInfo" resultType="Integer" parameterType="java.util.HashMap" useCache="false">
             SELECT
                    COUNT(*)
             FROM
                    BOARD
             <trim prefix="WHERE" prefixOverrides="AND | OR ">
                    <if test="where.fileType != null and where.fileType != ''">
                           AND FILE_TYPE = #{where.fileType}
                    </if>
                    <if test="where.regUser != null and where.regUser != ''">
                           AND REG_USER = #{where.regUser}
                    </if>
             </trim>
       </select>
            <where>태그의 오류를 대신한 것으로  where 엘리먼트는 태그에 의해 컨텐츠가 리턴되면 단순히 “WHERE”만을 추가한다. 
           게다가 컨텐츠가 “AND”나 “OR”로 시작한다면 그 “AND”나 “OR”를 지워버린다.
            
            2.<foreach>
        <update id="update">
             <foreach collection="list" item="item" index="index" open="INSERT ALL " separator=" " close="SELECT * FROM DUAL">
                     INTO BOARD(
                           SEQ
                           , NAME
                           , WRITER
                           <if test='item.modifyCause != null and item.modifyCause != "" and item.modifyCause != "-"'>
                           , MODIFY_CAUSE
                           </if>
                    ) VALUES
                    (
                           #{item.seq}
                           , #{item.name}
                           , #{item.writer}
                           <if test='item.modifyCause != null and item.modifyCause != "" and item.modifyCause != "-"'>
                           , #{item.modifyCause}
                           </if>
                    )
             </foreach>
       </update>
  1.  <choose>  
       SELCT *
       FROM
             <choose>
                    <when test="where.type eq 'tblboard1'.toString()">TBL_BOARD_1 TB_1</when>
                    <when test="where.type eq 'tblboard12'.toString()">TBL_BOARD_2 TB_2</when>
             </choose>
    4.bind
        <select id="selectBlogsLike" resultType="Blog">
        <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
        SELECT * FROM BLOG
        WHERE title LIKE #{pattern}
        </select>
mybatis의 plug-in
mybatis-config.xml
       <plugins>
           <plugin interceptor="com.util.MybatisInterceptor"/>
       </plugins>

mybatis에서는 plug-in을 이용하여 mybatis쿼리가 실행하는 시점에 간섭하여 사용자가 정의한 별도의 작업을 진행할수있다.

MybatisInterceptor.java
@Intercepts( {
    @Signature( type = Executor.class, method = "update", args = { MappedStatement.class, Object.class } ),
    @Signature( type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class } ),
    @Signature( type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class } ) } )
public class MybatisInterceptor implements Interceptor {
       @Override
       public Object intercept( Invocation invocation ) throws Throwable {
             Object args[] = invocation.getArgs();
             MappedStatement ms = (MappedStatement) args[0];
             String id = ms.getId();
             //로그 찍고 싶지않은 쿼리들 예외처리
             if ( "memberInfo.listMember".equals( id ) )
                    return invocation.proceed();
            
             //바인딩 변수 사용했을 경우 ?로 표시되므로 ?를 바인딩된 값으로 치환해준다. 
             BoundSql boundSql = ms.getBoundSql( args[1] );
             StringBuilder sql = new StringBuilder( boundSql.getSql() );
             if ( boundSql.getParameterMappings().size() > 0 ) {
                    ArrayList<ParameterMapping> parameterMappingsList = (ArrayList<ParameterMapping>) boundSql.getParameterMappings();
                    for ( int i = 0; i < parameterMappingsList.size(); i++ ) {
                        ParameterMapping parameterMapping = parameterMappingsList.get( i );
                        Object result = null;
                        String fieldName = parameterMapping.getProperty();
                        result = Ognl.getValue( fieldName, boundSql.getParameterObject() );
                        int index = sql.indexOf( "?" );
                        ....
                        sql.replace( index, index + 1, result );
                    }
             }

                            return sql;
       }

-prepared statement
쿼리가 실행되는 순서는 
구분분석(parse) >> 치환(bind) >> 실행(execute) >> 인출(patch) 과정을 거치는데  일반적인 statement를 사용하면 select쿼리를 입력했을때 매번 전과정을 수행한다. 하지만 prepared STatement를 사용하는 경우에는 효율을 높이기 위해 최초1번만 parse를 한다. 
 그리고 변경되는 값은 변수로 선언해주고 매번 값을 대입하여 사용하여아한다.  바인드 데이터는 sql문법이 아닌 내부의 인터프리터나 컴파일 언어로 처리하기 때문에 문법적인 의미를 가지지 않아 인젝션 공격에 안전하다. 













'STUDY > SPRING' 카테고리의 다른 글

@MVC (ing)  (0) 2018.11.12
Java EE 디자인패턴(ing)  (0) 2018.11.12
Aspect Oriented Programming  (0) 2018.11.06
TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02

+ Recent posts