반응형

JPA는 ORM, 객체와 테이블을 매핑하는 프레임워크를 말한다.

객체와 테이블을 정확하게 매핑하기 위해 다음과 같은 어노테이션들을 사용한다.

  • 객체와 테이블
    • @Entity - 테이블과 매핑할 클래스에 @Entity 어노테이션을 추가하는 것으로 해당 클래스가 데이터베이스와 매핑할 객체임을 알려줌.
      Entity의 중요한 3가지 원칙
      1. 기본 생성자를 꼭 가지고 있을 것
      2. final class, interface, enum, inner 클래스가 아닌 기본 클래스
      3. 저장할 필드에 final을 사용하지 말 
    • @Table - Entity와 매핑할 테이블의 이름으로 직접 지정
      @Table(schema = "Schema Name",  name="Table Name") 에서 처럼 schema 명칭과 table name으로 구성되어지며, schema 명은 생략가능하다.
      스키마 매핑과 테이블 매핑 외에 DDL 유니크 제약 조건 추가 및 Catalog 매핑을 추가할 수 있다.
  • 프라이머리 키 매핑
    • @Id - 프라이머리 키는 기본 키라고도 하며, 관계형 데이터베이스에서 각 레코드의 식별자로 이용하기에 적합한 후보 키 가운데, 설계자가 일반적으로 이용되어야 한다고 정해 놓은 것을 말한다. JPA에서는 가능한 프라이머리(기본)키를 1개만 지정할 것을 권장한다. 이를테면 MariaDB의 AUTO_INCREMENT와 같이 자동 증가하게 할 수 있고, 아니면 직접 기본 키를 지정할 수도 있다.
  • 필드와 컬럼 매핑
    • @GeneratedValue - 프라이머리(기본)키를 생성할 때 직접 할당과 자동 생성으로 나뉜다.
      @GeneratedValue(strategy = GenerationType.IDENTITY) 
      JPA에서 자동 생성에는 3가지 전략이 있다.
      1. IDENTITY : 프라이머리(기본)키 생성을 데이터베이스에 위임
      2. SEQUENCE : 데이터베이스 시퀀스를 이용해서 기본 키를 할당
      3. TABLE : 키 생성 테이블을 이
    • @Column - 필드 매핑. JPA에서 @Column을 명시하지 않으면 해당 필드의 이름으로 매핑한다.
      테이블의 컬럼명과 클래스의 필드명이 서로 다를 경우 @Column의 name속성을 이용해서 이러한 문제를 해결할 수 있으며, DDL 생성 기능으로 nullable은 null 제약 조건, length는 길이 제약 조건 등을 사용할 수 있다.
      @Column(name = "member_id", nullable = true, length = 20) 
    • @Enumerated - ENUM 타입 매핑
      @Enumerated 에는 2가지 타입이 있음.
      1. EnumType.ORDINAL
      2. EnumType.STRING
      ORDINAL은 Enum에 정의된 순서대로 JPA가 이용하며, 만약 순서가 변경된다면 가능한 STRING 타입을 이용하는 것이 좋다. STRING 타입은 데이터베이스에 문자로 저장된다.
  • 연관관계
    • @OneToOne - 일대일 매핑
    • @OneToMany - 일대다 매핑
    • @ManyToOne - 다대일 매핑
    • @ManyToMany - 다대다 매핑

 

반응형
반응형

resources 폴더 아래의 application.properties 파일을 열어서 하기의 내용을 추가한다.

 

pring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3306/dbname #db connection url
spring.datasource.username=dbuser #username
spring.datasource.password=pswd #password

#Runtime 콘솔 화면에 SQL 쿼리문을 나타낸다.
spring.jpa.show-sql=true
# Runtime 콘솔 화면에 나타나는 SQL 쿼리문을 깔끔하게 정렬해서 나타낸다.
spring.jpa.properties.hibernate.format_sql=true
#show sql - jpa가 생성하는 쿼리를 콘솔로 출력
spring.jpa.properties.hibernate.show_sql=true
#use sql comment
spring.jpa.properties.hibernate.use_sql_comments=true
# JPA 사용 시 초기화 및 생성 전략 설정 (create, update, create-drop, validate)
# 보통 라이브 환경에서는 update, validate를 사용하고 개발시에는 create, create-drop을 사용합니다.
# create : 매번 테이블 생성을 새로 시도합니다.
# update : 변경이 필요한 경우는 alter 명령이 실행되고, 테이블이 없는 경우 create 명령이 실행됩니다.
# create-drop : create와 동일하며 SessionFactory가 내려가면 테이블을 drop 시킵니다.
# validate : update와 동일하게 Object를 검사하지만 스키마는 건드리지 않고 데이터만 변경합니다. 스키마 구조가 다르면 에러를 발생시킵니다.
# none 아무것도 안함.
# @Entity 컴포넌트를 스캔하여, 서버 실행 시 Table "자동 생성" 및 서버 종료 시 Table "자동 삭제"한다.
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=true

# spring.datasource.initialization-mode=always 바뀜
# 서버실행시 자동 실행 src/main/resources/data.sql
spring.sql.init.mode=always
spring.jpa.defer-datasource-initialization=true

 

반응형
반응형

오라클에서 BLOB 정보를 가져오는 쿼리를 MyBatis를 이용해서 작성하는 경우 BLOB 정보를 Map 형태로 바로 받으면 안되며, 반드시 ResultMap으로 받아야 한다.

<resultMap type="java.util.Map" id="imgResult">
	<result column="IMG" property="IMG" javaType="[B" jdbcType="BLOB"/>
</resultMap>

Select 절에서는 resultType이 아닌 resultMap을 이용해서 imgResult로 설정해야 한다.

<select id="select_img" parameterType="java.util.Map" resultMap="imgResult">
	select img from img_table where id = #{id}
</select>

이렇게 가져온 이미지를 컨트롤 단에서 사용 방법은 아래와 같다.

Map<String, Object> imgMap = imageService.select_img(map);
byte[] arr = (byte[]) imgMap.get("IMG");

String base64Encode = null;
if (arr != null && arr.length > 0) {
	base64Encode = byteToBase64(arr);
    base64Encode = "data:image/png;base64," + base64Encode;
}

private static String byteToBase64(byte[] arr) {
	String result = "";
    
    try {
    	result = Base64Utils.encodeToString(arr);
    } catch (Exception e) {
    	e.printStackTrace();
    }
    return result;
}

이렇게 가져온 base64Encode 의 값을 JSP 또는 HTML의 img 태그에 src로 할당하면 이미지를 브라우저에서 바로 볼 수 있게 된다.

반응형

'Java 기반 Web > Java' 카테고리의 다른 글

MyBatis 에서 어의 없는 오류..ㅠㅠ  (0) 2022.05.28
반응형

jquery datepicker를 이용해서 년월만 선택하고 싶을 때가 있다.
이때 유용하게 사용할 수 있는 방법이다.
활용성을 높이기 위해 공통 js파일에 show_calendar_month라는 Function을 정의해서 사용했다. 이렇게 이용을 하면 사용하고자 하는 페이지에서 보다 유연하게 사용할 수 있다.
input 파라미터로는 선택한 년월을 표기할 textbox의 id를 넣어 주면 된다.
년월 picker 기능은 모두 Function에 정의해 두고 호출만 하면 된다.

function show_calendar_month(obj) {
	$("#" + obj).datepicker({
		monthNames: [ "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" ],
		monthNamesShort: [ "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" ],
        changeMonth: true,
        changeYear: true,
        showButtonPanel: true,
        dateFormat: 'yy-mm',
        onChangeMonthYear: function (year, month, inst) {
        	$(this).val($.datepicker.formatDate('yy-mm', new Date(year, month - 1, 1)));
    	},
        onClose: function(dateText, inst) { 
            var month = $("#ui-datepicker-div .ui-datepicker-month :selected").val();
            var year = $("#ui-datepicker-div .ui-datepicker-year :selected").val();
            $(this).datepicker('setDate', new Date(year, month, 1));
        },
        beforeShow : function(input, inst) {
            if ((datestr = $(this).val()).length > 0) {
                actDate = datestr.split('-');
                year = actDate[0];
                month = actDate[1]-1;
                $(this).datepicker('option', 'defaultDate', new Date(year, month));
                $(this).datepicker('setDate', new Date(year, month));
            }
        }
    });
    
    $("#" + obj).focus(function () {
        $(".ui-datepicker-calendar").hide();
    });
    
    $('#' + obj).datepicker('show');
}

이렇게 정의한 Function을 html/jsp 파일에서 아래와 같이 호출만 하면 된다.

...
<td class="c" width="250px">
	<input type=text id="Fdate1" name="Fdate1" value='<cnsone:date value="${Fdate1}"/>' readonly style="width:70px;text-align:center;">
	<input type='button' onClick="show_calendar_month('Fdate1');" style="background:url(${WEBROOT}/images/icon/calendar.gif);border:0;width:16px;height:18px;cursor:hand;vertical-align:middle;">
</td>
...

스타일 시트를 추가해서 기존에 보이던 일자를 보이지 않도록 처리한다.
<style>
table.ui-datepicker-calendar { display:none; }
</style>
달력 아이콘 버튼을 클릭하면 아래의 이미지와 같이 년월 picker의 모습을 보게 된다.
년과 월만을 선택하는 UI를 datepicker를 이용해서 간단하게 만들 수 있다.

그림1 - 년월 Picker
반응형
반응형

MyBatis 사용 도중 아래와 같은 오류 메시지 발생.

도대체 뭐가 문제일까?

처음엔 아래와 같은 오류로 인해 상당히 혼란 스러웠다.

뭐가 문제지??

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.NumberFormatException: For input string: "N"
### Cause: java.lang.NumberFormatException: For input string: "N"

 

실제 이 오류를 발생한 xml파일 내의 쿼리는 아래와 같다.

다이나믹 쿼리 수행을 위해 추가한 if 절로 인해 발생하는 것이었다. 문법 상의 문제가 없는지 여러번 살폈으나 별다른 이상을 발견하지 못했고, 구글링 도중 발견한 글 중 하나가 바깥에 표기한 큰따옴표(")를 작은따옴표(')로 변경해 보라는 글을 발견했다. 

<select id="select_CuttingAndNoCutting" resultMap="CuttingResult" parameterType="java.util.Map">
		SELECT  cutting_date, nvl(cut, 0) as cut, nvl(nocut, 0) as nocut 
		  FROM ( select cutting_date, sum(order_length) as order_length, cutting_type 
				   from ( SELECT cutting_date, order_length, cutting_type 
							from cutting_order_circuit
						   where cutting_date like #{YYYYMM,jdbcType=VARCHAR} || '%'
						     and drum_no not like '%결품%' 
							 and drum_no is not null 

							<if test="isPowerCutter == 'Y'">  
							 and (actor = #{actor,jdbcType=VARCHAR}
							  or actor is null 
							 and powerorder = 'on')  
							 and powercomplete is null
							</if>
						
							<if test="isPowerCutter == 'N'">  
							 and actor = #{actor,jdbcType=VARCHAR}
							</if>
						
						) group by cutting_date, cutting_type
			   ) PIVOT ( sum(order_length) FOR cutting_type IN ('절단' as cut, '미절단' as nocut))       
		order by cutting_date
	</select>

혹시나 하는 마음에 큰따옴표와 작은따옴표의 위치를 변경한 결과 아무런 문제 없이 내가 예상했던 대로 쿼리가 수행되는 것이었다.

정말 어의없는 상황..이 문제로 상당한 시간을 허비했거늘...

오늘도 이렇게 어의없이 문제를 깔끔하게(?) 해결한 하루 였다.

내가 바꾼 건 따옴표 밖에는 없었다는..

<select id="select_CuttingAndNoCutting" resultMap="CuttingResult" parameterType="java.util.Map">
		SELECT  cutting_date, nvl(cut, 0) as cut, nvl(nocut, 0) as nocut 
		  FROM ( select cutting_date, sum(order_length) as order_length, cutting_type 
				   from ( SELECT cutting_date, order_length, cutting_type 
							from cutting_order_circuit
						   where cutting_date like #{YYYYMM,jdbcType=VARCHAR} || '%'
						     and drum_no not like '%결품%' 
							 and drum_no is not null 

							<if test='isPowerCutter == "Y"'>  
							 and (actor = #{actor,jdbcType=VARCHAR}
							  or actor is null 
							 and powerorder = 'on')  
							 and powercomplete is null
							</if>
						
							<if test='isPowerCutter == "N"'>
							 and actor = #{actor,jdbcType=VARCHAR}
							</if>
						
						) group by cutting_date, cutting_type
			   ) PIVOT ( sum(order_length) FOR cutting_type IN ('절단' as cut, '미절단' as nocut))       
		order by cutting_date
반응형

'Java 기반 Web > Java' 카테고리의 다른 글

오라클 DB에서 BLOB 정보를 가져와서 보여주기  (0) 2022.07.20
반응형

jQuery UI의 Datepicker를 아래의 이미지와 같이 설정한다.

[그림 1] 구현 하고자 하는 Datepicker 모습

 

$('#workMfgDate').datepicker({

    dateFormat: "yy.mm.dd",

    monthNames: [ "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" ],
    monthNamesShort: [ "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" ],
    dayNamesMin: [ "일", "월", "화", "수", "목", "금", "토" ],
    firstDay: 1, 
    changeYear: true,
    changeMonth:true,
    showButtonPanel: true,
    gotoCurrent: true,
    closeText: "Clear",
    currentText: "오늘",
    showOn: "both",

    buttonImage: "./images/icon/monthlycalendar.png",

    buttonImageOnly: true

});

 

monthNames와 monthNamesShort 에 한글로 1~12월 까지의 명칭을 표기하도록 설정한다.
firstDay가 1이면 월요일, 0 이면  일요일 시작요일이 된다.
changeYear값이 true 이면 년을 선택할 수 있는 콤보박스가 제공된다.
changeMonth값이 true 이면 월을 선택할 수 있는 콤보박스가 제공된다.
showButtonPanel 값을 true로 하면 달력의 아래 부분에 Today/Close 버튼이 나타난다.
closeText는 Close버튼의 명칭을 말하며, 버튼의 명칭을 Clear로 변경하고 클릭 시 선택한 날짜 값을 지우고 달력을 숨기도록 바인딩 할 예정이다.
currentText는 Today버튼의 명칭을 오늘로 바꾸고 오늘 일자를 설정하고 달력을 숨기도록 바인딩 할 예정이다.
showOn 값을 both로 하게 되면 input 과 Image button 둘 다 사용할 수 있으며, button으로 설정할 경우 Image button을 클릭했을 때만 달력이 나타나게 된다.

buttonImage는 input 옆에 생기는 버튼에 아이콘을 추가할 수 있다.
buttonImageOnly 값이 true이면 버튼의 테두리는 제공되지 않고 이미지만 표시되며, false일 경우 버튼 위에 이미지가 있게 된다.

 

html 문서의 input type 설정 부분

<input type="text" id="workMfgDate" name="workMfgDate" readonly style="width:80px;text-align:center;">

 

jQuery UI Datepicker에서 showButtonPanel 값을 true로 설정을 했지만, Today 버튼을 클릭해도 아무런 반응이 없다.

따라서 오늘 날짜를 적용하고 창을 닫는 동작을 할 수 있도록 jQuery 바인딩 코드를 작성해야 한다.

 

오늘(Today) 버튼 클릭 시 오늘 날짜를 적용하고 창을 닫는다.

$('button.ui-datepicker-current').live('click', function() {

    $.datepicker._curInst.input.datepicker('setDate', new Date()).datepicker('hide').blur();

});

 

Close(Clear) 버튼 클릭 시 값을 지우고 창을 닫는다.

$('button.ui-datepicker-close').live('click', function() {

    $.datepicker._curInst.input.datepicker('setDate', '').datepicker('hide').blur();

});

반응형

+ Recent posts