spring-mvc/board

Spring legacy 프로젝트 게시판 만들기(1) - 설정

crone 2021. 6. 13. 23:56

spring으로 간단한 흐름과 기능적으로 동작하는 게시판을 만들 예정입니다.

 

 

Jungsangjin0/spring-board

Contribute to Jungsangjin0/spring-board development by creating an account on GitHub.

github.com


프로젝트 구조입니다.

프로젝트 구조

 

spring 에서 mybatis를 사용하기 위해 pom.xml에 dependency를 추가해준다. 그리고 jdbc의 dataSource를 사용하기 위해 dbcp도 추가해줍니다.

<!-- mybatis spring  -->
	<!-- mybatis -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis</artifactId>
		    <version>3.4.6</version>
		</dependency>
		
		<!-- mybatis와 spring을 연결해줄 dependncy -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis-spring</artifactId>
		    <version>1.3.2</version>
		</dependency>
		
		<!-- spring-jdbc 추가 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		
		<!-- dbcp 라이브러리 추가 -->
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
		</dependency>

db는 오라클을 사용할 예정이므로 오라클에서 제공하는 jdbc Driver를 사용하기위해 dependency를 추가 하겠습니다.

	<!-- jdbc  -->
		<dependency>
			<groupId>com.jslsolucoes</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.1.0</version>
		</dependency>

 

dataSource 설정하기

root-context에 dataSource에 대한 bean을 생성하여 설정해 줍니다.

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDrvier"/>
		<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/>
		<property name="username" value="board"/>
		<property name="password" value="board"/>
	</bean>

 

DataSource DI Test

root-context.xml에 설정한 bean(dataSource)가 잘 설정 되었는지 테스트를 진행합니다.

test는 프로젝트 구조 중 test > java 에 test Class를 만들어서 실행합니다.

 

먼저 test를 하기 위해 JUnit과 spring-test dependency를 pom.xml에 추가해준다.(JUnit은 version을 4.12로 변경해준다.)

<!-- spring test -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-test</artifactId>
		    <version>${org.springframework-version}</version>
		    <scope>test</scope>
		</dependency>
        
        <!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>   

 

참고) DataSource를 import 할때는 import javax.sql.DataSource 를 import 한다.

package diTest;

import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"})
public class DataSourceTest {

	@Autowired
	DataSource dataSource;
	
	private static final Logger log = LoggerFactory.getLogger(DataSourceTest.class);
	
	
	@Test
	public void dataSourceDITest() {
		log.info("dataSource : {}", dataSource);
		
	}
}

@Runwith 은 테스트 실행방법을 확장할 때 사용하는 어노테이션이고, @ContextConfiguration  bean을 설정한 context의 파일위치를 지정할 때 사용하는 어노테이션입니다. @Autowired 는 springContext로 부터 bean을 주입 받을때 (DI) 사용하는 어노테이션입니다.

 


+추가

위에서 테스트한 DataSource의 Connection 생성 test를 해보았는데 오류가 발생하였습니다..

- 테스트 코드

package diTest;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"})
public class DataSourceTest {

	@Autowired
	DataSource dataSource;
	
	private static final Logger log = LoggerFactory.getLogger(DataSourceTest.class);
	
	
	@Test
	public void dataSourceDITest() {
		try {
			Connection con = dataSource.getConnection();
			log.info("con : {}", con);
			assertNotNull(con);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		log.info("dataSource : {}", dataSource);
		
	}
}

 

org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'oracle.jdbc.driver.OracleDravier'
	at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1429)
	at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
	at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
	at diTest.DataSourceTest.dataSourceDITest(DataSourceTest.java:41)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)

찾아보니 BasicDataSource bean을 설정할 때 property로 설정한 driverClassName의 value에 오타가 있었습니다.

<!--잘못된 설정-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDravier"/> 
		<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/>
		<property name="username" value="board"/>
		<property name="password" value="board"/>
	</bean>
 
 <!--바꾼 설정-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> 
		<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/>
		<property name="username" value="board"/>
		<property name="password" value="board"/>
	</bean>

위에서 볼 수 있듯이 value의 마지막에 OracleDriver가 아닌 OracleDravier 의 오타가 이유였습니다..


 

 

 

 

JUnit Test

위와 같이 mybatis 사용에 필요한 SqlSessionFactoryBean과 sql명령을 실행할 sqlSessionTemplate의 bean을 생성해 줍니다.

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
		
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDrvier"/>
		<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/>
		<property name="username" value="board"/>
		<property name="password" value="board"/>
	</bean>
	
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
		<property name="mapperLocations" value="classpath:mybatis/mapper/*-mapper.xml"/>
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory"/>
	</bean>
</beans>

SqlSessionFactoryBean의 bean을 생성할 때 속성값으로 configLocation을 설정하는데 value값으로 mybatis 설정 xml 을 전달해줍니다. 경로는 war로 배포했을 때 경로를 기준으로 합니다. 

프로젝트 오른쪽 클릭 Export

 

Web - > WAR file

 

WAR 파일의 파일 구조를 보면 아래와 같습니다.

WAR파일 구조

classpath는 WEB-INF 아래 classes 부터 찾겠다는 뜻입니다. *-mapper.xml 는 xml 파일 이름이 -mapper로 끝나는      xml 파일들을 로드하겠다는 뜻 입니다. 

 

- mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration></configuration>

- board-mapper.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="board">
 
 </mapper>

 

 

 

test를 통해 bean들이 객체로 잘 생성되는지 확인 후에 테이블을 생성하였습니다.

create table board(
    board_id number, 
    board_category number not null, 
    board_writer varchar2(20) not null,
    board_title varchar2(200) not null,
    board_text varchar2(4000),
    board_date date default sysdate not null, 
    board_reply number,
    board_level number default 0 not null,
    board_status char(1) default 'N' not null
    
);
alter table board add primary key(board_id);
alter table board add constraint fk_board_reply_id foreign key(board_reply)
references board(board_id);

create sequence seq_board nocache;
commit;

board_category는 0이 일반 게시판으로 설정하였습니다.

db데이터

 

 

마지막으로 web.xml에 encoding filter를 추가해주었습니다.

web.xml 파일에 추가할 filter 태그

	<filter> 
		<filter-name>encodingFilter</filter-name> 
		<filter-class> org.springframework.web.filter.CharacterEncodingFilter </filter-class> 
		<init-param> 
			<param-name>encoding</param-name> 
			<param-value>UTF-8</param-value> 
		</init-param> 
		<init-param> 
			<param-name>forceEncoding</param-name> 
			<param-value>true</param-value> 
		</init-param> 
	</filter> 
	
	<filter-mapping> 
		<filter-name>encodingFilter</filter-name> 
		<url-pattern>/*</url-pattern> 
	</filter-mapping>

오류들

mapper의 namespace를 설정하지 않았을 때 나는 오류

<?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>
 
 </mapper>
<?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="">
 
 </mapper>
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
WARN : org.springframework.web.context.support.XmlWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in ServletContext resource [/WEB-INF/spring/root-context.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'. Cause: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in ServletContext resource [/WEB-INF/spring/root-context.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'. Cause: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1794)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:878)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
	at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:401)
	at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:292)
	at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:103)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4689)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5155)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1412)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1402)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'. Cause: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
	at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:523)
	at org.mybatis.spring.SqlSessionFactoryBean.afterPropertiesSet(SqlSessionFactoryBean.java:380)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790)
	... 21 more
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'. Cause: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:120)
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:92)
	at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:521)
	... 24 more
Caused by: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:110)
	... 26 more
6월 17, 2021 11:51:34 오전 org.apache.catalina.core.StandardContext listenerStart
심각: Context initialized 이벤트를 [org.springframework.web.context.ContextLoaderListener] 클래스의 인스턴스인 리스너에 전송하는 동안 예외 발생
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in ServletContext resource [/WEB-INF/spring/root-context.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'. Cause: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1794)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:878)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
	at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:401)
	at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:292)
	at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:103)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4689)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5155)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1412)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1402)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'. Cause: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
	at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:523)
	at org.mybatis.spring.SqlSessionFactoryBean.afterPropertiesSet(SqlSessionFactoryBean.java:380)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1790)
	... 21 more
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'file [E:\Dev\board\target\classes\mybatis\mapper\board-mapper.xml]'. Cause: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:120)
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:92)
	at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:521)
	... 24 more
Caused by: org.apache.ibatis.builder.BuilderException: Mapper's namespace cannot be empty
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:110)
	... 26 more

 

jstl이 적용되지 않아서 나는 오류

org.apache.jasper.JasperException: 절대 URI인 [http://java.sun.com/jsp/jstl/core]을(를), web.xml 또는 이 애플리케이션과 함께 배치된 JAR 파일 내에서 찾을 수 없습니다.
	at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:55)
	at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:293)
	at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:80)
	at org.apache.jasper.compiler.TagLibraryInfoImpl.generateTldResourcePath(TagLibraryInfoImpl.java:251)
	at org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:122)
	at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:431)
	at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:489)
	at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1445)
	at org.apache.jasper.compiler.Parser.parse(Parser.java:144)
	at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:244)
	at org.apache.jasper.compiler.ParserController.parse(ParserController.java:105)
	at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:203)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:375)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:351)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:335)
	at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:597)
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:399)
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:386)
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:330)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:713)
	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:462)
	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:387)
	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:315)
	at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:171)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1373)
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1118)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1057)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:543)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:615)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1626)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:834)

6월 17, 2021 12:17:57 오후 org.apache.catalina.core.StandardWrapperValve invoke
심각: 경로 [/board]의 컨텍스트 내의 서블릿 [appServlet]을(를) 위한 Servlet.service() 호출이, 근본 원인(root cause)과 함께, 예외 [절대 URI인 [http://java.sun.com/jsp/jstl/core]을(를), web.xml 또는 이 애플리케이션과 함께 배치된 JAR 파일 내에서 찾을 수 없습니다.]을(를) 발생시켰습니다.
org.apache.jasper.JasperException: 절대 URI인 [http://java.sun.com/jsp/jstl/core]을(를), web.xml 또는 이 애플리케이션과 함께 배치된 JAR 파일 내에서 찾을 수 없습니다.
	at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:55)
	at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:293)
	at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:80)
	at org.apache.jasper.compiler.TagLibraryInfoImpl.generateTldResourcePath(TagLibraryInfoImpl.java:251)
	at org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:122)
	at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:431)
	at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:489)
	at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1445)
	at org.apache.jasper.compiler.Parser.parse(Parser.java:144)
	at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:244)
	at org.apache.jasper.compiler.ParserController.parse(ParserController.java:105)
	at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:203)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:375)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:351)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:335)
	at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:597)
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:399)
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:386)
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:330)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:713)
	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:462)
	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:387)
	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:315)
	at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:171)
	at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316)
	at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1373)
	at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1118)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1057)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:543)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:615)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1626)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:834)

WEB-INF 아래 lib폴더를 만든 후

WEB-INF > lib folder

 

lib 폴더에 jstl.jar 를 넣어 준 후

jstl.jar

 

project build path library에 추가를 해줍니다.

java build path

 

jar 파일을 추가해주어도 되고 lib폴더를 User Library로 설정하여 추가해주는 방법도 있습니다.

Add Library
Add JARs