<mapper namespace="dev">
<select id="selectAll" resultType="dto">
select num, name, addr from mem
</select>
<select id="selectPart" parameterType="String" resultType="dto">
select num, name, addr from mem
where num=#{num}
</select>
<insert id="insertData" parameterType="formBean">
insert into mem values(#{num}, #{name}, #{addr})
</insert>
<update id="updateData" parameterType="formBean">
update mem set name=#{name}, addr=#{addr}
where num=#{num}
</update>
<delete id="deleteData" parameterType="String">
delete from mem where num=#{num}
</delete>
</mapper>
=> Login에 성공할 경우 redirect로 클라이언트에서 요청을 실행한 것과 같이 실행하여야한다. (forward를 사용하지
않음). Redirect로 list.jsp를 실행한다.
- LoginForm
@Component
public class LoginForm {
private String userid; // <form>태그의 name속성값과 동일하게 변수를 가진다.
private String passwd;
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
}
=> <form>태그의 name속성값과 동일하게 변수를 가지도록 작성한다. FormBean은 client의 요청을 처리할 때 사용
한다. DTO는 DB 자료를 처리할 때 사용. (용도에 따라 관례적으로 FormBean과 DTO를 사용한다)
- ListController
@Controller
public class ListController {
@RequestMapping("list")
public ModelAndView aaa() {
ModelAndView view = new ModelAndView("list");
view.addObject("msg", "로그인 성공으로 하고 뭔가를 출력함");
return view;
}
}
@Controller // 클라이언트로 부터 요청 받을 경우 동작
public class ListController {
@Autowired
private DataDao dataDao;
@RequestMapping("testdb") // url mapping
public ModelAndView listProcess() {
ArrayList<SangpumDto> list = dataDao.getDataAll();
return new ModelAndView("list", "datas", list); // list.jsp에 연결.
}
}
=> @Controller : 클라이언트로 부터 요청 받을 경우 동작.
@Autowired : setter injection 기능 수행.
@RequestMapping("url명") : url명과 동일한 url을 받을 경우 실행.
dataDao의 getDataAll()를 실행한 list값을 "datas" key에 넣어 실행한다.
- SangpumDto
public class SangpumDto {
private String code, sang, su, dan;
//getter/setter
}
@Controller // 클라이언트로 부터 요청 받을 경우 동작
public class ListController {
@Autowired
private DataDao dataDao;
@RequestMapping("testdb") // url mapping
public ModelAndView listProcess() {
ArrayList<SangpumDto> list = dataDao.getDataAll();
return new ModelAndView("list", "datas", list); // list.jsp에 연결.
}
}
=> DataSource와 동일
- SangpumDto
public class SangpumDto {
private String code, sang, su, dan;
//getter/setter
}
=> DataSource와 동일
- DataSourceMaria
@Repository() // DB연동
//@Repository("dataSource")
public class DataSourceMaria extends DriverManagerDataSource{
public DataSourceMaria() {
setDriverClassName("org.mariadb.jdbc.Driver");
setUrl("jdbc:mysql://127.0.0.1:3306/test");
setUsername("root");
setPassword("123");
}
}
=> DataSource와 동일
- DataDao
@Repository // DB 연결.
public class DataDao extends JdbcDaoSupport{
//@Autowired
//private DataSourceMaria dataSourceMaria; // DataDao에 주입됨.
//DataSource를 JdbcDaoSupport가 가지고 있으로 생성자를 이용한다.
public DataDao(DriverManagerDataSource dataSource) {
setDataSource(dataSource);
}
public List<SangpumDto> getDataAll(){
String sql="select * from sangdata";
return getJdbcTemplate().query(sql, new ItemRowMapper());
}
class ItemRowMapper implements RowMapper{
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
SangpumDto dto = new SangpumDto();
dto.setCode(rs.getString("code"));
dto.setSang(rs.getString("sang"));
dto.setSu(rs.getString("su"));
dto.setDan(rs.getString("dan"));
return dto;
}
}
}
=> extends JdbcDaoSupport : JdbcDaoSupport 상속 받아 기능을 수행한다.
=> @Autowird를 사용하면 DataDao객체에 dataSource가 setter injection됨으로 해당 기능이 정상동작하지않는다.
정상동작을 위해선 상속을 받고있는 JdbcDaoSupport객체에 setter injection을 하여야한다. 생성자를 이용하여
DataDao객체가 생성되면 setDataSource()가 실행되도록 하여 JdbcDaoSupport객체에 dataSource를 setter
=> 공유자원을 관리하는 root-context.xml에서 DB연결을 하도록, Sql문 mapping하는 DataMapper.xml관련 설정을
제외하고 삭제.
=> DataMapper파일과 alias를 정의한다.
- DataMapper.xml
<mapper namespace="dev">
<select id="selectAll" resultType="dto">
select * from sangdata
</select>
<select id="selectSearch" parameterType="formBean" resultType="dto">
select code, sang, su, dan from sangdata
where sang like concat('%',#{searchValue},'%')
</select>
</mapper>
=> sql문과 연결되는 Mapper 파일을 작성한다.(<mapper>태그 내부에 sql문을 형식에 맞춰 작성)
=> <select> : select문 작성 시 사용되는 태그. (id속성 - 외부에서 호출할 이름 / resultType - sql문을 실행한 결과
Type / parameterType속성 - 외부로 부터 받을 매개변수의 타입, #{변수명}에 매개변수가 대입된다.)
=> like concat('%', 검색어, '%') : 검색어가 포함된 결과 반환. ( like %검색어%)
@Controller
//@ComponentScan("pack.model")
public class ListController {
@Autowired // setter injection
private SangpumInter sangpumInter; // 다형성 사용
@RequestMapping("list")
public Model process(Model model){
model.addAttribute("data", sangpumInter.list());
// Model객체는 addAttribe(key, value) 메소드를 사용하여 값을 전달.
return model; // 받은 요청명 그대로 송부한다.
}
}
=> @Controller : Controller 기능 수행 (servlet 동작)
=> "list" url 받을 경우 동작한다. list()메소드를 실행한 결과를 "data" key에 넣어 list.jsp에 리턴한다.
- SangpumDto
public class SangpumDto {
private String code,sang, su, dan;
//setter, getter
}
=> DB연동에 사용되는 데이터는 Dto로 작성.(select)
- SangpumBean
public class SangpumBean {
// formBean : 수정, 삭제 등의 작업이 있다면 code, sang, su, dan도 처리
// 검색용
private String searchValue;
public String getSearchValue() {
return searchValue;
}
public void setSearchValue(String searchValue) {
this.searchValue = searchValue;
}
}
@Controller
//@ComponentScan("pack.model")
public class ListController {
@Autowired // setter injection
private SangpumInter sangpumInter; // 다형성 사용
@RequestMapping("list")
public Model process(Model model){
model.addAttribute("data", sangpumInter.list());
// Model객체는 addAttribe(key, value) 메소드를 사용하여 값을 전달.
return model; // 받은 요청명 그대로 송부한다.
}
}
=> xml방식과 동일
- SangpumDto
public class SangpumDto {
private String code,sang, su, dan;
//setter, getter
}
=> xml방식과 동일
- SangpumBean
public class SangpumBean {
// formBean : 수정, 삭제 등의 작업이 있다면 code, sang, su, dan도 처리
// 검색용
private String searchValue;
public String getSearchValue() {
return searchValue;
}
public void setSearchValue(String searchValue) {
this.searchValue = searchValue;
}
}
// MyBatis SQL mapping interface file
public interface SangpumAnnoInter {
@Select("select * from sangdata")
public List<SangpumDto> selectAllData();
@Select(" select code, sang, su, dan from sangdata where sang like concat('%',#{searchValue},'%')")
public List<SangpumDto> selectSearch(SangpumBean bean);
}
① Client요청을 Controller로 연결하기 ② 공유 객체 사용 ③ 패턴을 사용한 경로 매핑 ④ @annotation을 이용한 Controller호출 ⑤ Spring MVC Project를 사용 ⑥ @RequestParam 사용(get) * Controller 값 처리(기존) : getParameter() * Controller 값 처리(어노테이션 사용) * get 방식은 한글이 안깨지나 post 방식사용시 한글이 깨진다. Encording을 하여 한글 깨짐을 방지한다. ⑦ FormBean, @ModelAttribute 사용(post) * Controller 값 처리(기존) : getParameter() * Controller 값 처리(FormBean 사용) * Controller 값 처리(@ModelAttribute 사용)
=> 어노테이션 사용시 <context:component-scan>를 사용한다. pack package의 어노테이션이 동작하도록 한다.
- HelloController * Controller implemets(상속)을 사용할 경우
public class HelloController implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("veiw1"); // veiw1.jsp에 연결
modelAndView.addObject("message", "hello"); // 모델에 다녀왔다 가정. // key-value 전달.
return modelAndView;
}
}
=> hello-servlet.xml/world-servlet.xml에서 연결한 hello.do 요청 발생 시 실행된다.
=> handlerRequest() 메소드를 오버라이딩하여 request를 처리한다.
=> setVieName("파일명")으로 view1에 연결된다. .hello-servlet.xml 파일의 ViewResover 처리로 /views/view1.jsp파일이
연결된다.
=> addObject(key, value)를 이용하여 값을 전달한다.
* @Controller(어노테이션)을 사용할 경우
@Controller
@RequestMapping("hello.do") // 모든 메소드가 수행된다.
public class HelloController{
@RequestMapping(method=RequestMethod.GET)
//@RequestMapping("hello.do") // 해당 메소드만 실행된다.
public ModelAndView aaa() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("view1");
modelAndView.addObject("message", "hello aaa");
return modelAndView;
}
@RequestMapping(method=RequestMethod.POST)
//@RequestMapping("hello.do")
public ModelAndView bbb() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("view1");
modelAndView.addObject("message", "hello bbb");
return modelAndView;
}
}
=> hello-servlet.xml의 <context:component-scan>태그로 인해 @Controller가 동작한다.
@Controller : 클라이언트 요청에 따라 해당 클래스가 Controller동작을 하게된다.
@RequestMapping("요청명") : 요청명에 해당하는 요청이 들어올 경우 클래스가 실행된다.
@RequestMapping(method=RequestMethod.GET) : Get방식의 요청이 들어올때만 실행하게 한다.
@RequestMapping(method=RequestMethod.POST) : Post방식의 요청이 들어올때만 실행하게 한다.
=> ModelAndView객체를 리턴하도록 하여 값을 전달한다. 메소드명을 임의 지정 가능하다.
- WorldController * Controller implemets(상속)을 사용할 경우
public class WorldController implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("view2"); // veiw1.jsp에 연결
modelAndView.addObject("message", "hi world"); // 모델에 다녀왔다 가정. // key-value 전달.
return modelAndView;
}
}
=> HelloController와 동일
* @Controller(어노테이션)을 사용할 경우
@Controller
public class WorldController{
@RequestMapping({"/world.do","/good*.*","/hi/nice.do"}) // 여러개의 요청을 받을 수 있음.
//@RequestMapping("world.do")
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("view2"); // veiw1.jsp에 연결
modelAndView.addObject("message", "hi world"); // 모델에 다녀왔다 가정. key-value 전달.
return modelAndView;
}
@RequestMapping(value="/korea.do", method=RequestMethod.GET) // GET만 받을 수 있다.
//@RequestMapping({"/korea.do"})// Get과 Post를 모두 받을 수 있다.
public ModelAndView handleRequest2(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("view2"); // veiw1.jsp에 연결
modelAndView.addObject("message", "hi world korea"); // 모델에 다녀왔다 가정. key-value 전달.
return modelAndView;
}
@RequestMapping(value="/usa.*", method=RequestMethod.POST) // POST만 받을 수 있다.
//@RequestMapping(value="/usa.*", method=RequestMethod.GET) // GET만 받을 수 있다.
//@RequestMapping({"/usa.*"})
public ModelAndView handleRequest3(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("view2"); // veiw1.jsp에 연결
modelAndView.addObject("message", "hi world usa"); // 모델에 다녀왔다 가정. key-value 전달.
return modelAndView;
}
}
=> @RequestMapping({요청명1, 요청명2,..}) : 배열을 사용하여 여러개의 요청명을 받을 수 있다.
@RequestMapping(value="요청명", method=RequestMethod.GET) : 요청과 method 방식을 설정할 수 있다.
요청명에 * 를 사용하여 복수의 요청을 받을 수 있다.
- view1.jsp / view2.jsp
<body>
hello 결과 : ${requestScope.message}
</body>
=> Controller에서 addObject()메소드로 전달한 value를 key를 사용하여 받을 수 있다. (EL 사용 - ${key})
2) 공유 객체 사용
= spr4_share
- index.html
<body>
클래스 간 자원 공유<br>
<a href="hello.do">요청 1</a><br>
<a href="world.kor">요청2</a><br>
</body>
- web.xml
<!-- WebApplicationContext보다 먼저 수행 : 공유 자원 설정시 필요 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
=> applicationContext.xml에 공유자원을 설정한다.
<!-- WebApplicationContext에 의해 자동 수행 -->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- <load-on-startup> init() 메소드 호출 순서 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>world</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>world</servlet-name>
<url-pattern>*.kor</url-pattern>
<!-- <url-pattern>/</url-pattern> 모든 요청사항 -->
</servlet-mapping>
=> *.do 요청과 hello-servlet.xml 연결
=> *.kor요청과 world-servlet.xml 연결
- applicationContext.xml
<!-- 공유 자원 객체 생성 -->
<bean id="sharedData" class="pack.SharedData">
<property name = "shared" value="스프링 프로젝트 공유자원입니다."/>
</bean>
=> setter injection을 이용하여 공유자원 객체 shard에 value를 설정한다.
=>SimSimpleUrlHandlerMapping사용하여 <prop>에 경로 매핑 가능하다.
=> ?는 글자 갯수. * 복수개의 문자를 나타냄.
=> HelloController mapping의 name을 <prop>의 값으로 받아 패턴을 연결한다.
- HelloController
public class HelloController implements Controller{
private HelloModel helloModel;
//setter injection
public void setHelloModel(HelloModel helloModel) {
this.helloModel = helloModel;
}
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 모델 만들고 모델과 통신하기
String result = helloModel.getGreeting();
ModelAndView modelAndView = new ModelAndView();
//ModelAndView modelAndView = new ModelAndView("hello"); // ViewFile명
modelAndView.setViewName("hello");
modelAndView.addObject("result",result); // forword 방식(default)
//modelAndView.setViewName("redirect:/views/hello.jsp?result='d'"); // reditect 방식
return modelAndView;
}
}
=> Controller를 상속받고 handleRequest 오버라이딩하여 요청사항을 처리한다. => 기본 방식을 forward로 하여 /views/hello.jsp에 addObject(key, value)로 값을 전달한다. => setViewName("redirect:/views/hello.jsp")으로 redirect 가능하다.
@Controller
public class SangpumController {
@RequestMapping(value="sangpum", method=RequestMethod.POST)
public ModelAndView submit(HttpServletRequest request) {
String sang = request.getParameter("sang");
String su = request.getParameter("su");
String dan = request.getParameter("dan");
System.out.println(sang+" "+" "+su+" "+dan);
ModelAndView view = new ModelAndView();
view.setViewName("result");
view.addObject("data","good");
return view;
}
}
* Controller 값 처리(FormBean 사용)
@Controller
public class SangpumController {
@RequestMapping(value="sangpum", method=RequestMethod.POST)
public ModelAndView submit(SangpumBean bean) { // 지역 변수
//클라이언트로 부터 들어오는 데이터 양이 많을 경우 사용(form bean)
System.out.println(bean.getSang()+" "+" "+bean.getSu()+" "+bean.getDan());
ModelAndView view = new ModelAndView();
view.setViewName("result");
view.addObject("data","good");
return view;
}
}
=> 매개변수로 FormBean을 사용하여 값을 전달한다. bean의 범위는 {}안으로 지역변수로 사용된다.
* Controller 값 처리(@ModelAttribute 사용)
@Controller
public class SangpumController {
@Autowired // setter injection
private SangpumModel sanpumModel;
@RequestMapping(value="sangpum", method=RequestMethod.POST)
//public ModelAndView submit(SangpumBean bean) { // 지역 변수
public ModelAndView submit(@ModelAttribute("bean") SangpumBean bean) { // 전역변수
//클라이언트로 부터 들어오는 데이터 양이 많을 경우 사용(form bean)
System.out.println(bean.getSang()+" "+" "+bean.getSu()+" "+bean.getDan());
ModelAndView view = new ModelAndView();
view.setViewName("result");
view.addObject("data",sanpumModel.computeSangpum(bean));
return view;
}
}
=> 매개변수로 @ModelAttribute을 사용시 bean의 범위는 전역변수로 사용되어 addObject() 메소드를 사용하지않아도
다른 파일에서 접근이 가능하다.
- SangpumBean
@Component
public class SangpumBean { // form bean
private String sang; // 클라이언트로 부터 전달되어 오는 요청 Parameter값과 변수명을 동일하게 가져간다.
private int su, dan;
public String getSang() {
return sang;
}
public void setSang(String sang) {
this.sang = sang;
}
public int getSu() {
return su;
}
public void setSu(int su) {
this.su = su;
}
public int getDan() {
return dan;
}
public void setDan(int dan) {
this.dan = dan;
}
}
=> Form Bean 정의. Form Bean의 멤버변수는 <form>태그 하위 태그 name의 값과 동일하게 가져간다.
- SangpumModel
@Component // 객체생성
public class SangpumModel { // 비지니스 로직 처리를 하는 모델 영역의 클래스
public String computeSangpum(SangpumBean bean) {
int price = bean.getSu() * bean.getDan();
String data = "품명" + bean.getSang() + " , 금액은 "+price;
return data;
}
}
- result.jsp
<body>
post 결과 : ${data}
<br>
${bean.sang}
</body>
<!-- DriverManagerDataSource를 상속받은 db 연결 class 객체 생성. -->
<bean id="dataSource" class="pack.model.DataSourceMaria"></bean>
<!-- db연결 클래스 객체 생성 -->
<bean id="sangpumImpl" class="pack.model.SangpumImpl">
<!-- JdbcDaoSupport을 상속받았기 때문에 별도로 dataSource setter를 정의하지않아도 setter주입을 할 수 있다. -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 객체생성 -->
<bean id="businessImpl" class="pack.business.BusinessImpl">
<property name="sangpumInter" ref="sangpumImpl"/>
</bean>
public interface HelloInter {
void hello();
void hi();
}
- HelloInterImpl
public class HelloInterImpl implements HelloInter{
public HelloInterImpl() {
System.out.println("HelloInterImpl 생성자");
}
public void hello() {
System.out.println("hello 처리");
}
public void hi() {
System.out.println("hi 처리");
}
}
- WriteInter
public interface WriteInter {
void write();
}
- WriteInterImpl
public class WriteInterImpl implements WriteInter{ // 핵심 로직을 가진 클래스
public WriteInterImpl() {
System.out.println("WriteInterImpl 생성자");
}
public void write() {
System.out.println("write 수행");
}
}
- MyAspect
public class MyAspect { // 관심사항을 가진 클래스
public void myLogOn() {
System.out.println("핵심 메소드 수행전 로그온 작업");
}
public void myLogOut() {
System.out.println("핵심 메소드 수행후 로그아웃 작업");
}
public void mySecurity() {
System.out.println("핵심 메소드 수행전 보안설정");
}
}
- AspectProcess
public class AspectProcess { // 여러개의 관심사항들을 모아 처리하는 클래스
private MyAspect myAspect; // 관심사항 클래스. 여러개 가능
public void setMyAspect(MyAspect myAspect) {
this.myAspect = myAspect;
}
public Object logging(ProceedingJoinPoint joinPoint) throws Throwable{
Object object = null;
myAspect.myLogOn();
object = joinPoint.proceed(); // 메타파일에서 설정한 핵심 메소드 수행.
myAspect.myLogOut();
return object;
}
public Object logging2(ProceedingJoinPoint joinPoint) throws Throwable{
Object object = null;
myAspect.mySecurity();
object = joinPoint.proceed(); // 메타파일에서 설정한 핵심 메소드 수행.
return object;
}
}
=> 핵심 로직의 wri로 시작하고 메개변수가 0개 이상인 메소드가 호출될때 AspectProcess(Aspect를 처리하는) 클래스의 logging() 메소드가 실행된다.
=> 핵심 로직의 hel로 시작하고 메개변수가 0개 이상인 메소드 또는 hi로 시작하는 메소드가 호출될때 AspectProcess클래스의 logging2() 메소드가 실행된다.
- ArticleInter
public interface ArticleInter {
void select();
}
- ArticleDao
//@Component
//@Repository
@Repository("articleDao")
public class ArticleDao implements ArticleInter{
public void select() {
System.out.println("db의 상품 자료를 read");
}
}
- LogicInter
public interface LogicInter {
void selectData_process();
}
- LogicImpl
public class LogicImpl implements LogicInter{
private ArticleInter articleInter;
public LogicImpl() {
}
public LogicImpl(ArticleInter articleInter) {
this.articleInter = articleInter;
}
public void selectData_process() {
System.out.println("selectData_proces 수행");
articleInter.select();
}
}
@Service
public class LogicImpl implements LogicInter{
@Autowired
//@Qualifier("aticleDao")
private ArticleInter articleInter;
public void selectData_process() {
System.out.println("selectData_proces 수행");
articleInter.select();
}
}
- ProfileAdvice
public class ProfileAdvice { // Advice, Aspect
public Object abc(ProceedingJoinPoint joinPoint) throws Throwable{
//핵심 메소드 이름 얻기
String methodName = joinPoint.getSignature().toString();
System.out.println(methodName+" 시작 전 작업");
Object object = joinPoint.proceed(); // 핵심 메소드
System.out.println(methodName+" 처리 후 작업");
return object;
}
}
@Aspect
@Component
public class ProfileAdvice { // Advice, Aspect
@Around("execution(public void selectData_process())")
public Object abc(ProceedingJoinPoint joinPoint) throws Throwable{
//핵심 메소드 이름 얻기
String methodName = joinPoint.getSignature().toString();
System.out.println(methodName+" 시작 전 작업");
Object object = joinPoint.proceed(); // 핵심 메소드
System.out.println(methodName+" 처리 후 작업");
return object;
}
}
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop2.xml");
LogicInter inter = (LogicInter)context.getBean("logicImpl");
inter.selectData_process();
}
=> 핵심로직의 selectData_process()메소드 호출 시 profileAdvice클래스의 abc()메소드가 호출.
<!-- 객체 생성 : 어노테이션 -->
<context:component-scan base-package="aop3"/>
<!-- Aop 설정 -->
<aop:aspectj-autoproxy/>
* 스프링 AOP에서 용어
- Joinpoint : ‘클래스의 인스턴스 생성 시점’, ‘메소드 호출 시점’ 및 ‘예외 발생 시점’ 과 같이 어플리케이션을 실행할 때 특정 작업이 시작되는 시점을 의미.
- Advice : 조인포인트에 삽입되어 동작할 수 있는 코드를 말함.
- Pointcut : 여러 개의 조인포인트를 하나로 결합한(묶은) 것을 말함.
- Advisor : 어드바이스와 포인트컷을 하나로 묶어 취급한 것을 말함.
- Weaving : 어드바이스를 핵심 로직 코드에 삽입하는 것을 말함.
- Target : 핵심 로직을 구현하는 클레스.
- Aspect : 여러 객체에 공통으로 적용되는 공통 관점 사항을 말함.
1) AOP 구현
- LogicInter
public interface LogicInter {
void startProcess();
}
- LogicImpl
@Service // @Component와 동일하지만 가독성을 위해 Service기능을 사용하면 @Service를 사용.
public class LogicImpl implements LogicInter{
public LogicImpl() {
}
public void startProcess() {
System.out.println("핵심 로직 수행");
}
}
- aop4.xml
<!-- 어노테이션을 사용하여 객체 생성 -->
<context:component-scan base-package="aop4"/>
<!-- aop를 사용하도록 설정 -->
<aop:aspectj-autoproxy/>
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop4.xml");
LogicInter inter = (LogicInter)context.getBean("logicImpl");
// getBean의 매개변수 : @객체 생성할 클래스명을 첫글자 소문자로 변경하여 생성.
inter.startProcess();
}
- RunAspect
// 아이디가 같으면 핵심로직 수행, 다르면 수행하지않도록 구현.
@Component
@Aspect // 독립적으로 동작할 관심 로직 클래스에 사용
public class RunAspect {
@Around("execution(public void startProcess())")
// 핵심로직의 메소드를 선택. 해당메소드 호출시 관심 메소드 호출.
//@Around는 핵심로직 실행 전/후 모두 기능을 추가할 수 있다.
public Object trace(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("AOP 시작 : 핵심 로직 처리전 id 검증");
System.out.print("input id : ");
Scanner scanner = new Scanner(System.in);
String id = scanner.nextLine();
if(! id.equalsIgnoreCase("aa")) { //equalsIgnoreCase() 대소문자 구분하지않고 비교.
System.out.println("id 불일치하여 작업을 종료합니다.");
return null;
}
Object obj = joinPoint.proceed(); // 핵심 로직 수행.
return obj;
}
}
@Component
@Aspect
@Around("excution(핵심 로직의 메소드)")
public Object 관심메소드명(ProceedingJoinPoint joinPoint) throws Throwable{ .. }
=> id나 name 둘중 무엇을 사용해도 상관없으며, <ref bean="name">에서 name을 호출가능.
② 생성자 호출
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("money_init.xml");
MyInter inter = (MyInter)context.getBean("myProcess");
inter.inputMoney();
inter.showResult();
}
}
=> ApplicationContext 객체 생성시 xml에 연결된 모든 생성자가 호출되며, 각 객체가 생성된다.
=> context의 getBean()메소드로 객체를 get하여 메소드를 사용한다.
=> getBean() 메소드의 리턴값은 Object로 다형성을 사용하여 캐스팅하여 객체를 대입한다.
=> getBean() 리턴 객체도 다형성을 사용하여 interface 객체에 대입하여 사용하는 것을 지향한다.
③ MVC 패턴 및 다형성 활용한 프로그래밍
pakage
Controller(Servlet)
Model(Dto, Dao-sql)
Interface
BusinessInterface
ModelInterface
↑
↑
Class
BusinessClass
ModelClass
=> 다형성을 갖춘 MVC Pattern 작성을 지향하여 프로그래밍한다.
=> Controller의 Business Class에서 Model Interface를 호출하여 사용한다.
=> 각 모델은 다형성을 활용하여 테이블에 따른 Sql문을 호출하여 DB와 연결된다.
=> [src.main/java]에 작성한다.
-Business Interface
public interface MyInter {
void inputMoney();
void showResult();
}
-Business Class
public class MyProcess implements MyInter{
private MoneyInter inter;
private int result[];
public MyProcess(MoneyInter inter) {
this.inter = inter;
}
public void inputMoney() {
//키보드로 금액입력
try {
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(reader);
int myMoney=0;
System.out.println("금액입력");
String data = br.readLine();
myMoney = Integer.parseInt(data);
result = inter.calcMoney(myMoney);
} catch (Exception e) {
System.out.println("inputMoney err "+e);
}
}
public void showResult() {
//계산이 끝난 배열 자료 출력.
System.out.println("만원 : "+result[0]+"개");
System.out.println("천원 : "+result[1]+"개");
System.out.println("백원 : "+result[2]+"개");
System.out.println("십원 : "+result[3]+"개");
System.out.println("일원 : "+result[4]+"개");
}
}
=> 생성자에 모델의 interface 객체를 매개변수로 받아 사용.
- Model Interface
public interface MoneyInter {
int[] calcMoney(int money);
}
- Model Class
public class MoneyCalc implements MoneyInter{
public MoneyCalc() {
}
public int[] calcMoney(int money) {
//단위별 금액 건수 계산용
int result[] = new int[5];
int temp=0;
int len = result.length;
for(int i=0; i<len;i++) {
if(i == 0) {
result[i] = money/(int)Math.pow(10, (len-1-i));
temp=money%(int)Math.pow(10, (len-1-i));
continue;
}
result[i] = temp/(int)Math.pow(10, (len-1-i));
temp=temp%(int)Math.pow(10, (len-1-i));
}
return result;
}
}
③ 생성자 주입(construnctor injection)
- ShowData(Dao)
public class ShowData {
public String toAlias() {
return "홍길동";
}
public String toHobby() {
return "운동";
}
}
- MyProcess(Controller)
public class MyProcess { // 포함으로 약결합 진행
private int age;
private String name;
private ShowData showData; // Class Type
public MyProcess(int age, String name, ShowData showData) {
this.age = age;
this.name = name;
this.showData = showData;
}
public void printData() {
System.out.println(name+age+showData.toAlias()+showData.toHobby());
}
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("anno1.xml");
Abc abc = (Abc)context.getBean("abc");
abc.printData();
}
② @Component : 객체 생성
- SenderInter
public interface SenderInter{
void show();
}
- Sender
@Component // 객체 생성
public class Sender implements SenderInter{
public void show() {
System.out.println("show메소드 수행");
}
}
- Sender2
//@Component = @Component("Sender2")// 객체 생성
@Component("별명")
public class Sender2 implements SenderInter{
public void show() {
System.out.println("Sender2의 show메소드 수행");
}
}
③ @Service : @Component와 동일하나 Business 로직에서 사용한다.
④ @Autowired : setter가 내부적으로 정의되며, type에 의한 mapping 진행.
⑤ @Qualifier("아이디") : type에 대하여 mapping시 동일한 타입(같은 부모를 상속받는 자식) 객체가 복수인 경우
Qualifier의 아이디에 명시한 아이디로 mapping한다.
- SenderProcess
//@Component
//@Service
@Service("SenderProcess") //Component와 동일
public class SenderProcess { // 서비스를 하는 비지니스 로직
private String name = "tom";
@Autowired // xml의 type에 대한 mapping.
//@Qualifier("sender2") // 동일한 타입의 객체(상속받는 자식 객체)가 복수인 경우 id로 mapping
@Qualifier("별명")
private SenderInter senderInter;
//public void setSender(Sender sender) { // @Autowired사용시 삭제가능
// this.sender = sender;
//}
public void displayData() {
System.out.println("displayData의 name : " + name);
senderInter.show();
}
}
- xml
<context:annotation-config/> // @어노테이션을 사용가능하게 한다.
<bean id="senderProcess" class="anno2.SenderProcess"/>
<bean id="sender" class="anno2.Sender"/>
<bean id="sender2" class="anno2.Sender2"/>
// SenderInter를 상속하는 class가 복수가 되면 type으로 mapping하기 때문에 식별자가 필요하다.
<bean class="anno2.Sender"/>
// type에 대한 mapping으로 id가 없어도 mapping된다.
<context:annotation-config/> // 생략 가능
<context:component-scan base-package="anno2"/> // pakage의 @Component, @Service가 작성된 class의 Bean을 생성.
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("anno2.xml");
SenderProcess senderProcess = (SenderProcess)context.getBean("senderProcess");
senderProcess.displayData();
}