본문 바로가기
내가 쓰는 글/일상

웹 프로젝트 3일차 - 협상

by Diligejy 2019. 3. 29.

웹 프로젝트 3일차다.

 

어제 스트레스 받은 우리 반 사람들은 술자리를 가졌다.

당연히 나는 남아서 공부했다. 갈만한 상태가 아니었기 때문이다.

 

그런데 어제 저녁 다른 팀 팀장 친구와 대화하던 중 자소서를 쓴다는 얘길 듣고 

그 친구의 자소서를 피드백해주겠다고 했었다.

 

3시까지 마감이라고 하기에 나는 오전에 넘겨받고 대충 맞춤법만 봐주면 될 줄 알았다.

 

그런데 왠걸 3시 마감인줄 알았는데 12시 마감이라는 소식과 오전에 못나온다는 소식을 접했다. 

 

ㅡ,ㅡ;;;

멘붕....

 

그런데 선생님과 우리팀의 회의 도중 View 구현이 너무 안되어 있고 그 친구의 도움을 받아야한다는 얘기가 흘러나왔다.

하지만, 그 친구네 팀은 자기네 팀도 하기 바쁘다며 손사레를쳤다.

 

그 때 이걸 협상도구로 삼았다.

2시간 첨삭을 해주는 대신 View 구현 담당 팀원 옆에 붙어서 도와주는 것.

전화를 하며 협상한 끝에 성공.

 

 

자소서를 넘겨받아보니 상태가 심각했다.

 

자기소개는 1600자 1090자를 써놓으셨다.... 

문항은 9문항이나 되고, 자소서를 처음쓰셔서 그런지 몰라도 방향조차 제대로 잡히지 않았다.

시간이 없기에 방향까지 피드백하고 다시 수정하는 과정을 거칠 순 없었다.

 

그저 다듬는 작업만 할 수 있었다.

2시간 정말 짧았다.

 

그렇지만, 첨삭받은 친구의 만족도는 높았다.

해주고싶은 말은 많았으나, 경험을 쌓다보면 알게될 일이므로 입을 닫았다.

 

-------------------------------------------------------------------------------------------------------------------------------

 

오늘 잘하는 친구에게 Spring의 전반적인 흐름에 대해 강의를 들으면서 조언을 들었다.

"형, 백엔드는 언제든 새로운 상황이 발생할 수 있으니까 검색해서 찾아갈 수 있어야해.

그게 지식보다 더 중요한거야"

 

그래서 이 친구의 따뜻한 얘기를 듣고 열심히 찾아보고 있다.

 

JDBCTemplate으로 게시판을 구현하라고 하시기에 

 

우선 JDBCTemplate Spring 게시판이라고 구글에 검색해봤다. 이런 저런 글이 있었지만,

http://ojc.asia/bbs/board.php?bo_table=C17&wr_id=421

 

Lab30. spring framework게시판(답변글)(17기 허운행)

// Desc : 스프링프레임워크게시판(답변글)// Date : 2013.11.14// Writer : 허운행-BoardDAO.java-package onj.board.dao;import java.util.List;import org.springframework.dao.DataAccessException;import onj.board.model.BoardD…

ojc.asia

우선 이 글이 그나마 내 상황에 적합한거 같았다.

 

그런데 JDBCTemplate이란 거에 대해 제대로 알지 못하는 거 같아 API문서를 보았다.

 

org.springframework.jdbc.core

Class JdbcTemplate

  • All Implemented Interfaces:InitializingBean, JdbcOperations

    public class JdbcTemplate extends JdbcAccessor implements JdbcOperations

    This is the central class in the JDBC core package. It simplifies the use of JDBC and helps to avoid common errors. It executes core JDBC workflow, leaving application code to provide SQL and extract results. This class executes SQL queries or updates, initiating iteration over ResultSets and catching JDBC exceptions and translating them to the generic, more informative exception hierarchy defined in the org.springframework.dao package.

    Code using this class need only implement callback interfaces, giving them a clearly defined contract. The PreparedStatementCreator callback interface creates a prepared statement given a Connection, providing SQL and any necessary parameters. The ResultSetExtractor interface extracts values from a ResultSet. See also PreparedStatementSetter and RowMapper for two popular alternative callback interfaces.

    Can be used within a service implementation via direct instantiation with a DataSource reference, or get prepared in an application context and given to services as bean reference. Note: The DataSource should always be configured as a bean in the application context, in the first case given to the service directly, in the second case to the prepared template.

    Because this class is parameterizable by the callback interfaces and the SQLExceptionTranslator interface, there should be no need to subclass it.

    All SQL operations performed by this class are logged at debug level, using "org.springframework.jdbc.core.JdbcTemplate" as log category.

    NOTE: An instance of this class is thread-safe once configured.

 

 

 

jdbc의 core패키지에 있는 클래스이며 

자바에서는 lang object패키지 밑에 있는 클래스였다.

JDBC의 사용을 쉽게 해주고 공통적으로 하는 실수를 피하는 데 도움이 된다는 내용이었다.

 

콜백이 뭔지 궁금했다.

찾아도 잘 나오지 않았다.

 

https://brunch.co.kr/@kimkm4726/1

 

소프트웨어 개발자를 위한 Callback의 정석.

콜백이라는 주제로 첫 게시글을 작성하기 이전에, 브런치의 깔끔하고 세련된 디자인과 UI에 감탄하며... (하준호 멘토님 감사합니당 ♥) 콜백이란것을 공부하면서. 구글링을 통해 찾은 예제를 수도 없이 보았다. 그러나 콜백이 무엇인지에 대해 뚜렷한 정의를 내리지 못한 채 아몰랑. 답답함만을 느끼던 중 결국, 콜백은 'A가 B를 호출하여 B가 작업을 수

brunch.co.kr

이 문서에 따르면

콜백은 'A가 B를 호출하여 B가 작업을 수행하다 어떤 시점에서 다시 B는 A를 호출, 그 때 A가 작업을 수행'하는 것 이라고 정의되어있었다.

 

지금 이 과정까지 1시간이 걸렸다. 잘 하는 친구는 이 시간을 줄여야 한다고 조언해주었다.

목표는 게시판을 만드는 것이기에 조금 더 속도를 낼 수 있어야 한다는 의미였다.

 

ConstructorsConstructor and Description

JdbcTemplate()

Construct a new JdbcTemplate for bean usage.

JdbcTemplate(javax.sql.DataSource dataSource)

Construct a new JdbcTemplate, given a DataSource to obtain connections from.

JdbcTemplate(javax.sql.DataSource dataSource, boolean lazyInit)

Construct a new JdbcTemplate, given a DataSource to obtain connections from.

JdbcTemplate의 생성자는 다음과 같았다. 'DataSource라는 게 필요하구나' 

이래서 수업에서 지겹도록 DataSource를 들은거구나 라고 생각이 들었다.

근데 기억이 나질 않는다. OTL...

 

JdbcTemplate의 query관련 메소드는 정말 많았다.

 

<T> T query(PreparedStatementCreator psc, PreparedStatementSetter pss, ResultSetExtractor<T> rse)

Query using a prepared statement, allowing for a PreparedStatementCreator and a PreparedStatementSetter.

<T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse)

Query using a prepared statement, reading the ResultSet with a ResultSetExtractor.

void query(PreparedStatementCreator psc, RowCallbackHandler rch)

Query using a prepared statement, reading the ResultSet on a per-row basis with a RowCallbackHandler.

<T> java.util.List<T> query(PreparedStatementCreator psc, RowMapper<T> rowMapper)

Query using a prepared statement, mapping each row to a Java object via a RowMapper.

<T> T query(java.lang.String sql, java.lang.Object[] args, int[] argTypes, ResultSetExtractor<T> rse)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, reading the ResultSet with a ResultSetExtractor.

void query(java.lang.String sql, java.lang.Object[] args, int[] argTypes, RowCallbackHandler rch)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, reading the ResultSet on a per-row basis with a RowCallbackHandler.

<T> java.util.List<T> query(java.lang.String sql, java.lang.Object[] args, int[] argTypes, RowMapper<T> rowMapper)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, mapping each row to a Java object via a RowMapper.

<T> T query(java.lang.String sql, java.lang.Object[] args, ResultSetExtractor<T> rse)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, reading the ResultSet with a ResultSetExtractor.

void query(java.lang.String sql, java.lang.Object[] args, RowCallbackHandler rch)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, reading the ResultSet on a per-row basis with a RowCallbackHandler.

<T> java.util.List<T> query(java.lang.String sql, java.lang.Object[] args, RowMapper<T> rowMapper)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, mapping each row to a Java object via a RowMapper.

<T> T query(java.lang.String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse)

Query using a prepared statement, reading the ResultSet with a ResultSetExtractor.

void query(java.lang.String sql, PreparedStatementSetter pss, RowCallbackHandler rch)

Query given SQL to create a prepared statement from SQL and a PreparedStatementSetter implementation that knows how to bind values to the query, reading the ResultSet on a per-row basis with a RowCallbackHandler.

<T> java.util.List<T> query(java.lang.String sql, PreparedStatementSetter pss, RowMapper<T> rowMapper)

Query given SQL to create a prepared statement from SQL and a PreparedStatementSetter implementation that knows how to bind values to the query, mapping each row to a Java object via a RowMapper.

<T> T query(java.lang.String sql, ResultSetExtractor<T> rse)

Execute a query given static SQL, reading the ResultSet with a ResultSetExtractor.

<T> T query(java.lang.String sql, ResultSetExtractor<T> rse, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, reading the ResultSet with a ResultSetExtractor.

void query(java.lang.String sql, RowCallbackHandler rch)

Execute a query given static SQL, reading the ResultSet on a per-row basis with a RowCallbackHandler.

void query(java.lang.String sql, RowCallbackHandler rch, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, reading the ResultSet on a per-row basis with a RowCallbackHandler.

<T> java.util.List<T> query(java.lang.String sql, RowMapper<T> rowMapper)

Execute a query given static SQL, mapping each row to a Java object via a RowMapper.

<T> java.util.List<T> query(java.lang.String sql, RowMapper<T> rowMapper, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, mapping each row to a Java object via a RowMapper.

java.util.List<java.util.Map<java.lang.String,java.lang.Object>> queryForList(java.lang.String sql)

Execute a query for a result list, given static SQL.

<T> java.util.List<T> queryForList(java.lang.String sql, java.lang.Class<T> elementType)

Execute a query for a result list, given static SQL.

<T> java.util.List<T> queryForList(java.lang.String sql, java.lang.Class<T> elementType, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result list.

java.util.List<java.util.Map<java.lang.String,java.lang.Object>> queryForList(java.lang.String sql, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result list.

<T> java.util.List<T> queryForList(java.lang.String sql, java.lang.Object[] args, java.lang.Class<T> elementType)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result list.

java.util.List<java.util.Map<java.lang.String,java.lang.Object>> queryForList(java.lang.String sql, java.lang.Object[] args, int[] argTypes)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result list.

<T> java.util.List<T> queryForList(java.lang.String sql, java.lang.Object[] args, int[] argTypes, java.lang.Class<T> elementType)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result list.

java.util.Map<java.lang.String,java.lang.Object> queryForMap(java.lang.String sql)

Execute a query for a result Map, given static SQL.

java.util.Map<java.lang.String,java.lang.Object> queryForMap(java.lang.String sql, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result Map.

java.util.Map<java.lang.String,java.lang.Object> queryForMap(java.lang.String sql, java.lang.Object[] args, int[] argTypes)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result Map.

<T> T queryForObject(java.lang.String sql, java.lang.Class<T> requiredType)

Execute a query for a result object, given static SQL.

<T> T queryForObject(java.lang.String sql, java.lang.Class<T> requiredType, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result object.

<T> T queryForObject(java.lang.String sql, java.lang.Object[] args, java.lang.Class<T> requiredType)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result object.

<T> T queryForObject(java.lang.String sql, java.lang.Object[] args, int[] argTypes, java.lang.Class<T> requiredType)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a result object.

<T> T queryForObject(java.lang.String sql, java.lang.Object[] args, int[] argTypes, RowMapper<T> rowMapper)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, mapping a single result row to a Java object via a RowMapper.

<T> T queryForObject(java.lang.String sql, java.lang.Object[] args, RowMapper<T> rowMapper)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, mapping a single result row to a Java object via a RowMapper.

<T> T queryForObject(java.lang.String sql, RowMapper<T> rowMapper)

Execute a query given static SQL, mapping a single result row to a Java object via a RowMapper.

<T> T queryForObject(java.lang.String sql, RowMapper<T> rowMapper, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, mapping a single result row to a Java object via a RowMapper.

SqlRowSet queryForRowSet(java.lang.String sql)

Execute a query for a SqlRowSet, given static SQL.

SqlRowSet queryForRowSet(java.lang.String sql, java.lang.Object... args)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a SqlRowSet.

SqlRowSet queryForRowSet(java.lang.String sql, java.lang.Object[] args, int[] argTypes)

Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, expecting a SqlRowSet.

 

생각이 여기까지 미치자 JdbcTemplate의 생성자에 있는 DataSource에 대해 알아야 했다.

javax.activation

Interface DataSource

  • All Known Implementing Classes:FileDataSource, URLDataSource

    public interface DataSource

    The DataSource interface provides the JavaBeans Activation Framework with an abstraction of an arbitrary collection of data. It provides a type for that data as well as access to it in the form of InputStreams and OutputStreams where appropriate.

인터페이스였다. InputStream과 OutputStream에 관련된 인터페이스인걸로 보였다.

 

실제로 그런거 같았다.

Modifier and TypeMethod and Description

String getContentType()

This method returns the MIME type of the data in the form of a string.

InputStream getInputStream()

This method returns an InputStream representing the data and throws the appropriate exception if it can not do so.

String getName()

Return the name of this object where the name of the object is dependant on the nature of the underlying objects.

OutputStream getOutputStream()

This method returns an OutputStream where the data can be written and throws the appropriate exception if it can not do so.

메소드가 다 그런 스트림관련이었다.

그럼 JdbcTemplate에 DataSource가 들어간다는 의미는 InputStream과 OutputStream, ContentType이 관련된다는 것까지는 생각했다.

 

어찌저찌 해서 

@Override
public List getAll() {
List getAll = null;
String sql = "select * from boarder";

getAll = jdbcTemplate.query(sql, new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
BoardVo board = new BoardVo();

board.setNo(rs.getInt("no"));
board.setTitle(rs.getString("title"));
board.setViewcount(rs.getInt("viewcount"));
board.setRegdate(rs.getDate("regdate"));
board.setSubtitle(rs.getString("subtitle"));
board.setn_Id(rs.getString("n_id"));
board.setContentType(rs.getString("contentType"));
board.setContent(rs.getString("content"));

return board;
}
});
return getAll;
}

 

 

 

이렇게까지는 작성할 수 있었다.

근데 RowMapper가 무엇인지는 몰랐다.

분명 이걸 모르면 나중에 뭔가 막힐 거 같다는 느낌적인 느낌이 왔다.

org.springframework.jdbc.core

Interface RowMapper<T>

  • Type Parameters:T - the result typeAll Known Implementing Classes:BeanPropertyRowMapper, ColumnMapRowMapper, MappingSqlQueryWithParameters.RowMapperImpl, SingleColumnRowMapper, UpdatableSqlQuery.RowMapperImplFunctional Interface:This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

    @FunctionalInterface public interface RowMapper<T>

    An interface used by JdbcTemplate for mapping rows of a ResultSet on a per-row basis. Implementations of this interface perform the actual work of mapping each row to a result object, but don't need to worry about exception handling.SQLExceptions will be caught and handled by the calling JdbcTemplate.

    Typically used either for JdbcTemplate's query methods or for out parameters of stored procedures. RowMapper objects are typically stateless and thus reusable; they are an ideal choice for implementing row-mapping logic in a single place.

    Alternatively, consider subclassing MappingSqlQuery from the jdbc.object package: Instead of working with separate JdbcTemplate and RowMapper objects, you can build executable query objects (containing row-mapping logic) in that style.

    Author:Thomas Risberg, Juergen HoellerSee Also:JdbcTemplate, RowCallbackHandler, ResultSetExtractor, MappingSqlQuery

검색한 결과였다. ResultSet을 각 row로 매핑시켜주는데 쓰는 거란 의미 같았다.

 

 

피드백을 받았는데 Generics타입을 지정해주어야 한다는 얘기를 들었다.

 

getAll = jdbcTemplate.query(sql, new RowMapper() {
public BoardVo mapRow(ResultSet rs, int rowNum) throws SQLException {
BoardVo board = new BoardVo();

 

이렇게 수정했다.

 

 

오늘도 열심히 야근각이다.

언제까지 야근일지 모르지만 야근각

 

JdbcTemplate에서 

 

org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [select * from boarder]; nested exception is java.sql.SQLException: 부적합한 열 이름

 

이라는 Exception이 발생할 경우에는 select * from 테이블명을 썼을 가능성이 농후하다.

 

여기서 *는 쓸 수가 없다. 직접 필드명을 다 써줘야 한다.

이렇게 불편하기 때문에 Mybatis를 쓴다는 얘기를 들었다.

 

5시 51분이 되어서야 게시판 전체 출력을 구현했다....

울고싶다.

댓글