spring 설정 / 리스트 페이지 / list / 프로젝트 CRUD / AJAX / 정리 / 학원후기
1. 리스트 페이지 프로젝트 CRUD / AJAX / 정리
회사를 그만두고 6개월과정 국비를 받아서 java 웹을 만드는 학원을 다니면서 마지막 프로젝트를 했었다.
그 프로젝트에서 한 주제는 워크스페이스 별 팀별 프로젝트를 프로젝트별 일정별 관리가 용이하도록 만든 홈페이지였다 시간이 부족해서 하지 못한 기능이나 마지막에 와파일 오류로 못했던 것들도 많고 내가 한부분도 부족한게 많지만
배운게 많은 시간이였다.
기본적인 spring CRUD에 대해서 알았고 수업시간에 배웠지만 기억하지 못하거나 활용하지 못했던 부분에 대해서 좀 더 배우는 시간이 된거 같다. 특히나 아직도 기억해야 하고 아직도 헷갈리는 부분은 A라는 controller 에서 B라는 controller로 데이터를 넘겨주는 부분을 자유롭게 활용하지 못한다는 것이다 좀 더 공부가 필요하고 응용을 하는 능력과 노하우가 필요할거 같다. 헤쉬맵, 맵, 서블렛을 사용하는 방법 또한 더 익혀야 할 거 같다고 느꼈다.
학원이 끝난지는 좀 됐지만 SQLD 시험 공부도 제대로 못하고 시험보고... 일주일이 지난거 같다 지금 정리해야 나중을 위해서라도 도움이 될거 같아 나를 위한 블로그를 만들었고 정리를 시작한다.
내가 보기위한 메모로 자세한 설명같은 것은 내가 필요할때만 하는 것으로 할 것
2. 완성된 페이지 화면
내가 만든 화면 Project List 부분이다.
회원가입 후 워크스페이스에 참여하고 소속된 워크스페이스 내에서만 새 project를 만들 수 있다 project는 워크스페이스에 참여한 사람들 모두가 생성할 수 있다 project list에 제목을 누르면 업무를 작성하고 체크하는 곳으로 넘어간다
이부분은 내가 한 부분이 아니기 때문에 우선 내가 한 부분을 먼저 살펴보겠다.
3.project list 코드
먼저 ajax를 많이 사용했는데 새글을 등록하는 Add Project를 누르면 모달이 뜨고 모달에서 작성되면 controller로
보내는 코드를 작성해야해서 script 코드가 꽤 길다 프로젝트에 참여할 워크스페이스 멤버도 가져와야해서...
3-1. 계정설멍 / DB 연동 / MySql 연결
생각해보니 스프링 설정하는 것이나 web.xml / pom.xml 이런거 적지 않았다
여기다가 적어야겠다. MySql을 사용했고 계정 설정은 spring - appServlet - root-context.xml 에서 했다.
root-context.xml파일 일부
<!-- beans for mybatis & mybatis-spring -->
<!-- SqlSessionFactoryBean.getObject()를 호출해서 SqlSessionFactory 생성 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="apacheDataSource" />
<property name="configLocation"
value="classpath:mybatis-config.xml" />
</bean>
<bean id="sessionTemplate"
class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
</bean>
<mybatis-spring:scan base-package="com.team.mapper" />
<bean id="workspaceService"
class="com.team.service.WorkspaceServiceImpl">
<property name="workspaceMapper" ref="workspaceMapper" />
</bean>
<bean id="memberService" class="com.team.service.MemberServiceImpl">
<property name="memberMapper" ref="memberMapper"></property>
</bean>
<bean id="projectService" class="com.team.service.ProjectServiceImpl">
<property name="projectMapper" ref="projectMapper"/>
</bean>
<!-- 여기에 연결될 DB 계정정보 적음 -->
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="" />
<property name="port" value="" />
<property name="username" value="teamplan" />
<property name="password" value="" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>
web/xml 에는 filter와 root-context.xml 파일위치를 나타내는 context-param
servlet-context.xml 파일위치를 저장하는 serblet이 있다.
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- filter : 서블릿 또는 JSP가 호출되기 전에 실행되는 모듈 -->
<!-- 여기서는 모든 요청에 대해 utf-8 encoding 설정 -->
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
다 기억이 나는건 아니니 나중에 찾아보기 쉽도록 정리하는거다.
pom.xml에 설정파일은 각 홈페이지마다 설정하는게 다르니 이부분에 대해서 기억이 나지 않으면 찾아야 할거 같고
버전이나 그런건 https://mvnrepository.com/ 여기에서 검색해서 추가하는 것으로 아래처럼 Maven/ Gradle중 사용하는걸로 복사해서 붙여넣으면 된다. 나는 Maven은 좀 알겠는데 Gradle은 기억이 잘안난다
++ /team/src/main/resources (프로젝트의 resources 부분에 mapper가 들어가는쪽)
새파일을 만들어서 (file) env.properties 라는 이름으로 mysql 계정정보를 담았다
(username / password / driver / url / 접속주기같은거 등)
datasource.driver=com.mysql.jdbc.Driver
datasource.url=jdbc:mysql://@아이피:포트/team?serverTimezone=Asia/Seoul
datasource.username=계정
datasource.password=비밀번호
datasource.minidle=20
datasource.maxpool=100
datasource.conntimeout=30000
maxActive : 최대 접속가능 커넥션 수 (사실상 가장 중요하다고 생각한다. DB에 동시에 접속 가능 커넥션이 많아야 성능이 좋아진다고 볼 수 있다.)
maxIdle : Idle상태의 최대 갯수
minIdle : idle상태의 최소 갯수
4. project lirst 코드
<!-- Navbar -->
<%@include file="/WEB-INF/views/modules/topbar.jsp" %>
<!-- /.navbar -->
<div class="wrapper">
<!-- Main Sidebar Container -->
<%@include file="/WEB-INF/views/modules/sidebar.jsp" %>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark">Project List</h1>
</div><!-- /.col -->
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item active">Project</li>
</ol>
</div><!-- /.col -->
</div><!-- /.row -->
</div><!-- /.container-fluid -->
</div>
<!-- /.content-header -->
<!-- Main content -->
<section class="content">
<!-- 최근 프로젝트 -->
<div class="card">
<div class="card-header">
<h3 class="card-title">최근 프로젝트</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse" data-toggle="tooltip" title="Collapse">
<i class="fas fa-minus"></i></button>
<!-- <button type="button" class="btn btn-tool" data-card-widget="remove" data-toggle="tooltip" title="Remove">
<i class="fas fa-times"></i></button> -->
</div>
</div>
<div class="card-body" style="display: block;">
<div class="card-body pb-0">
<div class="row d-flex align-items-stretch list-container2">
<jsp:include page="list2.jsp" />
</div>
</div>
</div>
</div>
<!-- /최근프로젝트 -->
인클루드 include
상단 하단 사이드 기타 계속 불러와야 하는건 인클루드 했다.
<% %> 서버용 주석
<%include file="/WEB-INF/폴더명/파일명 %>
<!-- 최근프로젝트 --> 안에 있는 include 부분이 모달로 연결되는 부분이다
<jsp:include page=list2.jsp />
list와 list2는 리스트의 내가속한 프로젝트 / 최근프로젝트 부분을 두개로 나눈것이다.
코드상 이렇게 하는게 맞고 이 안에 c:choose cLwhen c:foEach 부분으로 리스트를 반복적으로 가져오는 부분이 담겨있다 물론 list2(최근프로젝트) 부분은 최근에 추가된 4개의 목록만 가져오고 진행상황구분이 ajax로 변경되는데 내가 속한 프로젝트에서 변경하면 최근프로젝트에서 바로 변경이 안되는 문제가 (둘다 모달이여서) 발생해서 최근 프로젝트에서는 제거했다.
prlist는 list 전체다 나머지는 보면 알겠지 prdetail2는 테스트용으로 뭘하려고 만들었던건데 ajax 때문에 확인해보려고 만든거 같다 사용하지 않는다.
<!-- 내가 속한 프로젝트 -->
<div class="card">
<div class="card-header">
<h3 class="card-title">내가 속한 프로젝트</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse" data-toggle="tooltip" title="Collapse">
<i class="fas fa-minus"></i></button>
<!-- <button type="button" class="btn btn-tool" data-card-widget="remove" data-toggle="tooltip" title="Remove">
<i class="fas fa-times"></i></button> -->
</div>
</div>
<div class="card-body" style="display: block;">
<div class="card-body pb-0">
<div class="row d-flex align-items-stretch list-container1">
<jsp:include page="list.jsp" />
</div>
</div>
</div>
<button type="button" class="btn btn-block btn-outline-secondary btn-flat" data-toggle="modal" data-target="#modal-lg">
<i class="fas fa-plus"></i> Add Project
</button>
</div>
<!-- /.내가속한프로젝트 -->
<div class="modal fade" id="modal-lg">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<jsp:include page="prwrite.jsp" />
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<div class="modal fade" id="modal-detail2">
<div class="modal-dialog modal-lg">
<div id="projectDetailModal-container" class="modal-content">
<jsp:include page="prdetail.jsp" />
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
</section>
<!-- /.content -->
<form id="detail-form" action="detail.action" method="get">
<input type="hidden" id="projectNo" name="projectNo">
</form>
<form id="task-form" action="task.action" method="get">
<input type="hidden" id="projectNo" name="projectNo">
</form>
</div>
<!-- /.content-wrapper -->
<!-- footer -->
<%@include file="/WEB-INF/views/modules/footer.jsp" %>
<!-- Control Sidebar -->
<aside class="control-sidebar control-sidebar-dark">
<!-- Control sidebar content goes here -->
</aside>
<!-- /.control-sidebar -->
</div>
<!-- ./wrapper -->
나머지 코드인데 설명은 하지 않고 내가 보면 아니 넘어가는 것으로
일단 여기서 form에 id="detail-form" / id="task-form" 부분은 디테일과 업무쪽으로 넘어가는 부분에 projectNo를 넘겨주려고 만든거고 list에서 나중에 링크로 보낼때 쓴 부분이다 하나씩 볼것
5. List 불러오기
<%@ page pageEncoding="utf-8" contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<style>
.iconPublic { float: left; margin: 5px; font-size: 14px; }
a { color: #343a40;}
a:hover { color: #527aa2;}
.info-box .progress { height: 15px;}
</style>
<c:choose>
<c:when test="${not empty projectCount}">
<c:forEach items="${ projectCount }" var="project">
<div class="col-md-3 col-sm-6 col-12 projectChk">
<div class="info-box bg-info">
<div class="info-box-content">
<c:if test="${ project.proPublic eq 'false'}"><span class="iconPublic"><i class="fas fa-user-lock"></i></span></c:if>
<c:if test="${ project.proPublic eq 'true'}"><span class="iconPublic"><i class="fas fa-globe"></i></span></c:if>
<a class="task" href="javascript:" data-projectNo="${ project.projectNo }" >
<span class="info-box-text" style="font-weight: 500;">${ project.projectName }</span>
</a>
<c:if test="${ project.content == null}"><span class="progress-description"> </span></c:if>
<c:if test="${ project.content eq project.content }"><span class="progress-description" style="height: 23px;">${ project.content }</span></c:if>
<span class="info-box-number">
<div style="display:none" id="${ project.projectNo }" class="projectNo">${project.projectNo }</div>
<select name="proNo" class="seletProNo btn btn-block btn-default" style="display: inline-block;" >
<c:if test="${project.proNo eq '1' }">
<option value="1" selected="selected">상태없음 </option>
<option value="2">진행중 </option>
<option value="3">완료 </option>
<option value="4">보류 </option>
<option value="5">취소 </option>
</c:if>
<c:if test="${project.proNo eq '2' }">
<option value="1">상태없음 </option>
<option value="2" selected="selected">진행중 </option>
<option value="3">완료 </option>
<option value="4">보류 </option>
<option value="5">취소 </option>
</c:if>
<c:if test="${project.proNo eq '3' }">
<option value="1">상태없음 </option>
<option value="2">진행중 </option>
<option value="3" selected="selected">완료 </option>
<option value="4">보류 </option>
<option value="5">취소 </option>
</c:if>
<c:if test="${project.proNo eq '4' }">
<option value="1">상태없음 </option>
<option value="2">진행중 </option>
<option value="3">완료 </option>
<option value="4" selected="selected">보류 </option>
<option value="5">취소 </option>
</c:if>
<c:if test="${project.proNo eq '5' }">
<option value="1">상태없음 </option>
<option value="2">진행중 </option>
<option value="3">완료 </option>
<option value="4">보류 </option>
<option value="5" selected="selected">취소 </option>
</c:if>
</select>
<a class="to-detail" href="javascript:" data-projectNo="${ project.projectNo }" >
<span style="float: right; margin:20px 0 0;"><i class="fas fa-cog"></i></span>
</a>
</span>
<div class="progress">
<c:choose>
<c:when test="${ project.probability eq 'NaN'}">
<div class="progress-bar" style="width: 0%;">
<span style=" font-weight: 800; color: #527aa2; margin-left: 10px;">0%</span>
</div>
</c:when>
<c:otherwise>
<div class="progress-bar" style="width:${project.probability}%;">
<span style=" font-weight: 800;">
<fmt:formatNumber value="${project.probability}" pattern=".0"/>%
</span>
</div>
</c:otherwise>
</c:choose>
</div>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
</c:forEach>
</c:when>
<c:otherwise>
<div style="text-align:center; margin-top: -80px;">
<img style="width:75%" src="/team/resources/img/project_null.jpg">
</div>
</c:otherwise>
</c:choose>
강사님이 코딩하는 사람은 반복적인걸 싫어하고 줄여야 간결하고 좋은 코드가 나온다고 했는데 그래서 진행상황구분을 줄여보려고 노력했지만 못해서... 결국 반복적인 코드로 사용했다 ㅠㅠ.. 다음엔 더 좋은 간결한 코드를 사용할 수 있게 되지 않을까 싶다.
뭔가 아래처럼 줄여보려고 노력을 했는데 뭔갈 잘못쓰거나... projectNo eq '1'과 같다면 상태없음 이게 하나씩 반복적으로 해야하고 아니면 다음으로 넘어게 해야해서 c:choose 를 썼어야 했나 하고 시간이 없어서 시도해보지 못했다.
<%--
<select name="proNo2" class="selectProNo2 btn btn-block btn-default">
<option>
<c:if test="${project.proNo eq '1' }">상태없음</c:if>
<c:if test="${project.proNo eq '2' }">진행중</c:if>
<c:if test="${project.proNo eq '3' }">완료</c:if>
<c:if test="${project.proNo eq '4' }">보류</c:if>
<c:if test="${project.proNo eq '5' }">취소</c:if>
</option>
</select>
--%>
끊어서 마저 써야겠다