jpa 겟 스타트에 보면

메모리 DB를 쓰고 있고

datasource 프로퍼티 설정은 안나온다.


applicatoin.properites에서 설정하면 된다.


spring.datasource.url = jdbc:mysql://localhost:3306/dbname?useSSL=false

spring.datasource.username = username

spring.datasource.password = password

애노테이션에 AOP를 걸려고 검색했더니 애노테이션 이름만 달랑 걸어긴거 따라했더니 안된다.

aspectJ 표현식도 import랑 마찬가지라 package 찾아서 간다.

같은 패키지면 이름만 걸어도 찾지만 다를 경우 패키지 명까지 풀네임 적어줘야 한다.


예) @Around("@annotation(test.annotation.ConfigureProperties)")

ConfigurerAdapter 클래스에 다음과 같은 설정을 해주면 DB에서 인증을 할 수 있다.

@Autowired     private PasswordEncoder passwordEncoder;     @Autowired

DataSource dataSource; @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { String selectUserQuery = "select id, password, enabled from user where id = ?"; String selectRolesQuery = "select id, roles from user_roles where id = ?"; auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(selectUserQuery)

.authoritiesByUsernameQuery(selectRolesQuery);

}

시큐리티 쿼리 실행은 JDBCTemplate을 통해서 이뤄진다.

?에는 username 파라메터가 들어간다.

userByUsernameQuery는 select username, password, enabled 순이다.

authoritiesByUsernameQuery는 select username, authorities 순이다.


default setting에 순서에 맞게 매칭 시켜준다.




인터넷에서 spring security를 검색하면 한글 자료는 대부분 xml 설정으로 되어있다.

먼저 web.xml에 DelegateFilterProxy를 설정하는 것부터 나온다.

그리고 나머지 설정을 외우거나 복붙해서 만든다.

반면 java 설정은 자동완성과 클래스를 들여다 보기때문에 공부하는데 더 좋다.

설정도 web.xml에 필터를 등록할 필요 없다.


먼저 필요한 dependency 설정을 한다.
        <dependency>
  		<groupId>org.springframework.security</groupId>
  		<artifactId>spring-security-web</artifactId>
  		<version>5.0.0.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework.security</groupId>
  		<artifactId>spring-security-config</artifactId>
  		<version>5.0.0.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework.security</groupId>
  		<artifactId>spring-security-taglibs</artifactId>
  		<version>5.0.0.RELEASE</version>
  	</dependency>
자바 설정은 다음 클래스로 시작한다.

@Configuration

@EnableWebSecurity

public class CustomSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter


클래스로 시작하면 된다.


클래스 멤버는 다음과 같다.


아이디와 패스워드 권한을 설정한다. 시작은 인메모리 방식으로~~
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
          .withUser("user1").password("user1Pass")
          .authorities("ROLE_USER");
    }

    }

경로에 권한 설정과 로그인 페이지 설정을 한다. 로그인 페이지 설정을 안하면 브라우저 prompt로 인증을 요구한다. 로그인 페이지 url을 설정안하면 디폴트 로그인 페이지가 나온다.
        @Override
	protected void configure(HttpSecurity http) throws Exception {
		
		logger.info("http: "+http);
		
		http.httpBasic(); 
		http.authorizeRequests().antMatchers("/main/**").hasRole("USER");		
		http.formLogin().loginPage("/login")
			.usernameParameter("username").passwordParameter("password")
			.permitAll()
			.and();
	}
spring-security 시작은 단순하다.


Invalid character found in method name. HTTP method names must be tokens


https 요청 처리 안되있는데 요청이 들어올 경우


프로토콜을 잘 보길

기초적인 스프링 강의를 다 들었다면 누구나 설정할 수 있겠지만

차분히 하나씩 집어 보기로 한다.


JDBC : 자바와 데이터베이스를 연결시켜주는 기술

Java DataBase Connectivity

우리가 꼭알아야 할 것은 커넥션 풀을 만들어주는 DataSource
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.1.RELEASE</version>
</dependency>
를 받아서 보면 DataSource 관련 클래스가 있다. DriverManagerDataSource가 있다.
설정을 프로퍼티에 넣어서 빈 등록하면 된다.
apache commons에서 나온 SimpleDataSource나 BasicDataSource같은 것들도 있다.
여기서는 최근에 빠르다고 하는 hikari를 써보겠다. 
메이븐
<dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>2.7.2</version>
</dependency>
빈 등록
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="dataSourceClassName" value="com.mysql.jdbc.Driver" />
<property name="dataSourceProperties">
<props>
<prop key="url" >jdbc:mysql//localhost:3306/wook</prop>
<prop key="user">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>

SqlSession : statement를 만들고 실행한다.

jsp부터 공부했다면 Statement와 execute() 메서드, ResultSet들을 알것이다.
이를 편리하게 쓰게 해주는 ibatis의 클래스다.
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory" >
<property name="dataSource" ref="dataSource" />
</bean>
openSession이란 메서드로 SqlSession을 가져온다.

이렇게 오픈하고 클로즈하는게 귀찮을 수 있다.
<bean class="org.mybatis.spring.SqlSessionTemplate" >
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
SqlSessinTemlate을 쓰면 오픈, 커밋, 클로즈의 귀찮음을 피할 수 있다.

이렇게만 설정하면 
org/apache/ibatis/transaction/TransactionFactory  가 없다고 에러가 발생한다.
많이 봤던 getConnection(), close(), commit(), rollback()같은 메서드가 있는 인터페이스다.

메이븐 등록을 해준다.
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.5</version>
</dependency>


다른 dataSource를 쓴다고 spring jdbc를 메이븐 주입안했다면 

org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy

를 찾는 에러가 발생한다. spring-jdbc도 필요하다.

트랜잭션 결과가 의도한 상태가 아닐 경우 

일일이 조건문을 만들어 에러코드를 설정하는 것은 번거롭고 중복 코드를 발생시키는 일이다.

간단히 입셉션으로 처리하고 입셉션을 따로 관리하는 클래스와 페이지를 만든다면 편리다.

스프링은 이를 위해 Interface HandlerExceptionResolver를 사용한다.

빈등록에는 많은 방법들이 있는데

@ControllerAdvice 애노테이션을 이용하는 방법이 있다.

@ControllerAdvice(value="test.mapping") public class ExceptionAdivisor { @ExceptionHandler(InsertException.class) public ModelAndView handleInsertException(InsertException e) { System.out.println("ControllerAdvice: "+e); ModelAndView mav = new ModelAndView("/common/insertError"); mav.addObject("exception", e); return mav; } }


사용 방법은 아주 간단하다.

@ControllerAdvice(value="적용 패키지") 를 적용한 클래스를 만들고

@ExceptionHandler(예외 클래스) 를 적용한 메서드를 만들면 된다.

파라메터로 입섹션을 받을 수 있고

return값은 뷰리졸버에 의해 처리 되기때문에 ModelAndView를 적용할 수 있다.

@ControllerAdvice가 아닌 @Controller 클래스에 @ExceptionHandler 메서드를 적용한다면

해당 클래스에서 발생하는 예외에 우선권을 가지고 처리한다.


하지만 스프링에서는 이것보다는 SimpleMappingExceptionResolver를 이용한 입셉션처리를 권장하고 있다.

SimpleMappingExceptionResolver를 상속받아  커스텀 클래스를 만들면

ajax와 페이지 이동 방식등을 구분해서 사용할 수 있는 등 좀 더 디테일하게 예외처리를 할 수 있다.

이부분은 아직 공부가 덜 되서 다음에 쓰도록 하겠습니다.


transact는 거래하다라는 뜻이다. 

transaction은 DB와의 거래가 완전히 이루어진후 commit하는 것을 말한다.

그렇지 않으면 rollback을 한다.


Mapper자동 설정을 했을 때

transaction을 어떻게 처리할 것인가 고민할 것입니다.


스프링에는 트랜잭션을 관리해주는 클래스가 있습니다.

이를 aop를 이용해서 활용하면 됩니다.



<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"> </property></bean> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes>      <tx:method name="*" rollback-for="Exception"></tx:method> </tx:attributes> </tx:advice> <bean id="myAdvice" class="test.mapping.Advisor"></bean> <aop:config> <aop:pointcut id="requiredTx" expression="execution(* test..*Impl.*(..))"> <aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx"></aop:advisor> </aop:pointcut></aop:config>


(코드 프리티파이 xml처리가 안되서 보기가 이상하나 양해바랍니다.)


누구나 한번 쯤 

sqlSessionFactory.openSession()

sqlSession.쿼리

sqlSession.close() 

이 중복코드가 귀찮다고 생각해봤을 것이다.


이를 위해서 MyBatis에서는 interface를 이용한 자동 매퍼 설정을 만들어났다.

@MapperScan이라는 애노테이션을 이용하면 된다.


1. 일단 @Configuration 클래스를 만든다.

@Configuration @MapperScan(basePackages="test.mapping", annotationClass=Mapper.class) public class MapperConfigurer { }

2. 매퍼 인터페이스를 만든다.

@Mapper public interface DynamicMapper { @Select("select * from lcate where seq = #{num }") public List<Map> selectList(Map num);

@Insert("insert into lcate(code, name) values('003', '김성욱')") public int insertListMember(); }

편의상 xml 파일을 만들지 않고 애노테이션을 사용해서 쿼리문을 만들었다.

3. @Autowired로 다음과 같이 Injection을 한다.

@Autowired
DynamicMapper dynamicMapper;

4. 메서드를 호출한다

dynamicMapper.insertListMeber(); 와 같이 호출하면 된다.


XML설정

advice 클래스

public class Advisor {

public String returner(ProceedingJoinPoint joinPoint, HttpServletRequest req) throws Throwable  {

String URI = req.getRequestURI();

String contextPath = req.getContextPath();

joinPoint.proceed();

System.out.println("after");

System.out.println(URI);

System.out.println(contextPath);

String returnURI = URI.substring(contextPath.length()); 

return returnURI;

}

}

advice를 등록한다.

<bean id="myAdvice" class="com.zxy.Advisor" >

AOP-Config설정을 한다

<aop:config>

<aop:aspect ref="myAdvice">

<aop:pointcut id="myPointCut" expression="execution(* test..*Controller.*(..)) and args(req)" />

<aop:around method="returner" pointcut-ref="myPointCut" />

</aop:aspect>

<aop:aspect ref="myAdvice">

<aop:pointcut id="myPointCut2" 

expression="execution(* test..*(javax.servlet.http.HttpServletRequest, String)) and args(req, ctg)" />

<aop:around method="returner3" pointcut-ref="myPointCut2" />

</aop:aspect>

</aop:config>

<aop:aspect>태그의 ref는 참조할 advice bean id

<aop:pointcut> aspect적용 지점
     expression : 적용할 메서드 경로
execution은 메서드 전체 형식으로 지정한다.
접근제한자 반환타입 패키지를 포함한 메서드명 (인자)
<aop:around> method는 aspect로 동작할 메서드
   pointcut-ref는 참조할 pointcut id


HttpServletRequest를 받아서 URI를 받아 쓰고 싶은 경우가 생길 것이다.

파라메터를 받아 쓰고 싶은 경우는

execution에서 지정한 메서드 인자를 (..) 대신 타입을 패키지를 포함해서 써주고 args()도 추가해 주어야 한다.

(javax.servlet.http.HttpServletRequest, String) and args(req, ctg)

args()의 인자는 변수명을 쓴다.


+ Recent posts

티스토리 툴바