diff --git a/build.gradle b/build.gradle
index 8883efe..07b8889 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,46 +1,38 @@
plugins {
+ id 'org.springframework.boot' version '2.7.17'
+ id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id 'java'
- id 'idea'
}
-idea {
- module {
- inheritOutputDirs = false
- outputDir = file('./webapp/WEB-INF/classes')
- }
-}
-
-group 'org.example'
-version '1.0-SNAPSHOT'
+group = 'org.example'
+version = '1.0-SNAPSHOT'
+sourceCompatibility = '17' // 현재 프로젝트 SDK 17에 맞춤
repositories {
mavenCentral()
}
-ext {
- springVersion = "5.1.8.RELEASE"
- tomcatVersion = '8.5.42'
-}
-
dependencies {
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
- testImplementation "org.springframework:spring-test:$springVersion"
- testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
+ // Web
+ implementation 'org.springframework.boot:spring-boot-starter-web'
+
+ // JPA
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
- implementation("org.springframework:spring-jdbc:$springVersion")
- implementation("org.springframework:spring-web:$springVersion")
- implementation "org.reflections:reflections:0.10.2"
+ // JSP
+ implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
+ implementation 'javax.servlet:jstl:1.2'
- implementation("org.apache.commons:commons-dbcp2:2.6.0")
+ // DB Drivers (둘 다 두되 실제 사용 DB는 properties로 선택)
+ runtimeOnly 'com.h2database:h2'
+ runtimeOnly 'com.mysql:mysql-connector-j'
- runtimeOnly("com.h2database:h2:2.1.214")
- runtimeOnly('mysql:mysql-connector-java:8.0.28')
+ // Lombok
+ compileOnly 'org.projectlombok:lombok'
+ annotationProcessor 'org.projectlombok:lombok'
- implementation("org.apache.tomcat.embed:tomcat-embed-core:$tomcatVersion")
- implementation("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.5.2")
- implementation("org.apache.tomcat.embed:tomcat-embed-jasper:$tomcatVersion")
- implementation group: 'javax.servlet', name: 'jstl', version: '1.2'
- implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.7.1'
+ // Test
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
diff --git a/java-webMVC.ipr b/java-webMVC.ipr
index fddddb4..8db9230 100644
--- a/java-webMVC.ipr
+++ b/java-webMVC.ipr
@@ -1,79 +1,841 @@
-
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
@@ -83,7 +845,7 @@
-
+
@@ -94,11 +856,11 @@
-
+
-
+
-
+
\ No newline at end of file
diff --git a/java-webMVC.iws b/java-webMVC.iws
index d5bc759..cee9022 100644
--- a/java-webMVC.iws
+++ b/java-webMVC.iws
@@ -1,207 +1,702 @@
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+ {
+ "associatedIndex": 8
+}
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+ {
+ "keyToString": {
+ "Application.WebServerLauncher.executor": "Run",
+ "Gradle.Download Sources.executor": "Run",
+ "Gradle.KUIT6_Server-webMVC [:WebServerLauncher.main()].executor": "Run",
+ "ModuleVcsDetector.initialDetectionPerformed": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager": "true",
+ "RunOnceActivity.git.unshallow": "true",
+ "git-widget-placeholder": "hyungyu-week6",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "project.structure.last.edited": "Project",
+ "project.structure.proportion": "0.15",
+ "project.structure.side.proportion": "0.2",
+ "settings.editor.selected.configurable": "reference.settingsdialog.project.gradle",
+ "vue.rearranger.settings.migration": "true"
+ }
+}
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ localhost
+ 5050
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
-
-
-
-
+
+
+
-
-
- localhost
- 5050
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
false
-
-
+
+
+ 1760073220701
+
+
+ 1760073220701
+
+
+
+
+
+
+
+
+
+
+
+
+ 1760075337917
+
+
+
+ 1760075337917
+
+
+
+ 1760077817644
+
+
+
+ 1760077817644
+
+
+
+ 1760078525270
+
+
+
+ 1760078525270
+
+
+
+ 1760078833695
+
+
+
+ 1760078833695
+
+
+
+ 1760078862910
+
+
+
+ 1760078862910
+
+
+
+ 1760090670851
+
+
+
+ 1760090670851
+
+
+
+ 1760091132492
+
+
+
+ 1760091132492
+
+
+
+ 1760092283939
+
+
+
+ 1760092283939
+
+
+
+ 1760093173666
+
+
+
+ 1760093173666
+
+
+
+ 1760093238481
+
+
+
+ 1760093238481
+
+
+
+ 1760093436059
+
+
+
+ 1760093436059
+
+
+
+ 1760097040162
+
+
+
+ 1760097040162
+
+
+
+ 1760098311786
+
+
+
+ 1760098311786
+
+
+
+ 1760098426542
+
+
+
+ 1760098426542
+
+
+
+ 1760099467220
+
+
+
+ 1760099467220
+
+
+
+ 1762064598750
+
+
+
+ 1762064598750
+
+
+
+ 1762065836795
+
+
+
+ 1762065836795
+
+
+
+ 1762065865401
+
+
+
+ 1762065865401
+
+
+
+ 1762065914451
+
+
+
+ 1762065914451
+
+
+
+ 1762090236820
+
+
+
+ 1762090236820
+
+
+
+ 1762101354196
+
+
+
+ 1762101354196
+
+
+
+ 1762101374215
+
+
+
+ 1762101374215
+
+
+
+ 1762101404984
+
+
+
+ 1762101404984
+
+
+
+ 1762101989299
+
+
+
+ 1762101989299
+
+
+
+ 1762102380687
+
+
+
+ 1762102380687
+
+
+
+ 1762105085472
+
+
+
+ 1762105085472
+
+
+
+ 1762107116946
+
+
+
+ 1762107116946
+
+
+
+ 1762447381859
+
+
+
+ 1762447381859
+
+
+
+ 1762449706393
+
+
+
+ 1762449706393
+
+
+
+ 1762451139407
+
+
+
+ 1762451139407
+
+
+
+ 1762494085174
+
+
+
+ 1762494085174
+
+
+
+ 1762496092340
+
+
+
+ 1762496092340
+
+
+
+ 1762497104350
+
+
+
+ 1762497104350
+
+
+
+ 1762497155607
+
+
+
+ 1762497155607
+
+
+
+ 1762497185743
+
+
+
+ 1762497185743
+
+
+
+ 1762497518625
+
+
+
+ 1762497518625
+
+
+
+ 1762497902755
+
+
+
+ 1762497902755
+
+
+
+ 1762498361991
+
+
+
+ 1762498361991
+
+
+
+ 1762498379945
+
+
+
+ 1762498379945
+
+
+
+ 1762499142149
+
+
+
+ 1762499142149
+
+
+
+ 1762526307890
+
+
+
+ 1762526307890
+
+
+
+ 1762526318893
+
+
+
+ 1762526318893
+
+
+
+ 1762526975580
+
+
+
+ 1762526975580
+
+
+
+ 1762526985197
+
+
+
+ 1762526985197
+
+
+
+ 1762527191050
+
+
+
+ 1762527191050
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/WebServerLauncher.java b/src/main/java/WebServerLauncher.java
deleted file mode 100644
index d111fcf..0000000
--- a/src/main/java/WebServerLauncher.java
+++ /dev/null
@@ -1,22 +0,0 @@
-import org.apache.catalina.startup.Tomcat;
-
-
-import java.io.File;
-import java.util.logging.Logger;
-
-public class WebServerLauncher {
- private static final Logger logger = Logger.getLogger(WebServerLauncher.class.getName());
-
- public static void main(String[] args) throws Exception {
- String webappDirLocation = "./webapp/";
- Tomcat tomcat = new Tomcat();
- tomcat.setPort(8080);
- tomcat.getConnector();
-
- tomcat.addWebapp("", new File(webappDirLocation).getAbsolutePath());
- logger.info("configuring app with basedir: " + new File(webappDirLocation).getAbsolutePath());
-
- tomcat.start();
- tomcat.getServer().await();
- }
-}
diff --git a/src/main/java/core/db/MemoryUserRepository.java b/src/main/java/core/db/MemoryUserRepository.java
deleted file mode 100644
index 5654968..0000000
--- a/src/main/java/core/db/MemoryUserRepository.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package core.db;
-
-import jwp.model.User;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-public class MemoryUserRepository {
- private Map users = new HashMap<>();
- private static MemoryUserRepository memoryUserRepository;
-
- private MemoryUserRepository() {
- }
-
- public static MemoryUserRepository getInstance() {
- if (memoryUserRepository == null) {
- memoryUserRepository = new MemoryUserRepository();
- return memoryUserRepository;
- }
- return memoryUserRepository;
- }
-
- public void addUser(User user) {
- users.put(user.getUserId(), user);
- }
-
- public User findUserById(String userId) {
- return users.get(userId);
- }
-
- public Collection findAll() {
- return users.values();
- }
-
- public void changeUserInfo(User user) {
- if (users.get(user.getUserId()) != null) {
- users.put(user.getUserId(), user);
- }
- }
-}
diff --git a/src/main/java/core/db/Repository.java b/src/main/java/core/db/Repository.java
deleted file mode 100644
index e2f2bde..0000000
--- a/src/main/java/core/db/Repository.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package core.db;
-
-import jwp.model.User;
-
-import java.util.Collection;
-
-public interface Repository {
- void addUser(User user);
- User findUserById(String id);
- Collection findAll();
-}
diff --git a/src/main/java/core/jdbc/ConnectionManager.java b/src/main/java/core/jdbc/ConnectionManager.java
deleted file mode 100644
index 6673010..0000000
--- a/src/main/java/core/jdbc/ConnectionManager.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package core.jdbc;
-
-import org.apache.commons.dbcp2.BasicDataSource;
-
-import javax.sql.DataSource;
-import java.sql.Connection;
-import java.sql.SQLException;
-
-public class ConnectionManager {
- private static final String DB_DRIVER = "org.h2.Driver";
- private static final String DB_URL = "jdbc:h2:~/jwp-basic";
- private static final String DB_USERNAME = "sa";
- private static final String DB_PW = "";
-
- private static BasicDataSource ds;
- public static DataSource getDataSource() {
- if (ds == null) {
- ds = new BasicDataSource();
- ds.setDriverClassName(DB_DRIVER);
- ds.setUrl(DB_URL);
- ds.setUsername(DB_USERNAME);
- ds.setPassword(DB_PW);
- }
- return ds;
- }
-
- public static Connection getConnection() {
- try {
- return getDataSource().getConnection();
- } catch (SQLException e) {
- throw new IllegalStateException(e);
- }
- }
-}
diff --git a/src/main/java/core/web/filter/CharacterEncodingFilter.java b/src/main/java/core/web/filter/CharacterEncodingFilter.java
deleted file mode 100644
index b62058e..0000000
--- a/src/main/java/core/web/filter/CharacterEncodingFilter.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package core.web.filter;
-
-import javax.servlet.*;
-import javax.servlet.annotation.WebFilter;
-import java.io.IOException;
-
-@WebFilter("/*")
-public class CharacterEncodingFilter implements Filter {
- private static final String DEFAULT_ENCODING = "UTF-8";
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- request.setCharacterEncoding(DEFAULT_ENCODING);
- response.setCharacterEncoding(DEFAULT_ENCODING);
- chain.doFilter(request, response);
-
- }
-
- @Override
- public void destroy() {
- }
-
-}
diff --git a/src/main/java/core/web/filter/ResourceFilter.java b/src/main/java/core/web/filter/ResourceFilter.java
deleted file mode 100644
index 519fe1f..0000000
--- a/src/main/java/core/web/filter/ResourceFilter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package core.web.filter;
-
-
-import javax.servlet.*;
-import javax.servlet.annotation.WebFilter;
-import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-@WebFilter("/*")
-public class ResourceFilter implements Filter {
- private static final Logger logger = Logger.getLogger(ResourceFilter.class.getName());
- private static final List resourcePrefixs = new ArrayList<>();
- static {
- resourcePrefixs.add("/css");
- resourcePrefixs.add("/js");
- resourcePrefixs.add("/fonts");
- resourcePrefixs.add("/img");
- resourcePrefixs.add("/favicon.ico");
- }
-
- private RequestDispatcher defaultRequestDispatcher;
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- this.defaultRequestDispatcher = filterConfig.getServletContext().getNamedDispatcher("default");
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- HttpServletRequest req = (HttpServletRequest) request;
- String path = req.getRequestURI().substring(req.getContextPath().length());
- if (isResourceUrl(path)) {
- logger.log(Level.INFO, "path: "+ path);
- defaultRequestDispatcher.forward(request, response);
- } else {
- chain.doFilter(request, response);
- }
- }
-
- private boolean isResourceUrl(String url) {
- for (String prefix : resourcePrefixs) {
- if (url.startsWith(prefix)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void destroy() {
- }
-
-}
diff --git a/src/main/java/jwp/WebServerLauncher.java b/src/main/java/jwp/WebServerLauncher.java
new file mode 100644
index 0000000..3472976
--- /dev/null
+++ b/src/main/java/jwp/WebServerLauncher.java
@@ -0,0 +1,11 @@
+package jwp;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class WebServerLauncher {
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(WebServerLauncher.class, args);
+ }
+}
diff --git a/src/main/java/jwp/controller/HomeController.java b/src/main/java/jwp/controller/HomeController.java
index 751e468..d112d1f 100644
--- a/src/main/java/jwp/controller/HomeController.java
+++ b/src/main/java/jwp/controller/HomeController.java
@@ -1,18 +1,24 @@
package jwp.controller;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.annotation.WebServlet;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
+import jwp.dao.QuestionDao;
+import jwp.model.Question;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
-@WebServlet("/")
-public class HomeController extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- RequestDispatcher rd = req.getRequestDispatcher("/home.jsp");
- rd.forward(req, resp);
+import java.sql.SQLException;
+import java.util.List;
+
+@Controller
+@RequiredArgsConstructor
+public class HomeController {
+ private final QuestionDao questionDao;
+
+ @GetMapping("/")
+ public String showHome(Model model) throws SQLException {
+ List questions = questionDao.findAll();
+ model.addAttribute("questions", questions);
+ return "home";
}
}
diff --git a/src/main/java/jwp/controller/QnaController.java b/src/main/java/jwp/controller/QnaController.java
new file mode 100644
index 0000000..7efc062
--- /dev/null
+++ b/src/main/java/jwp/controller/QnaController.java
@@ -0,0 +1,66 @@
+package jwp.controller;
+
+import jwp.dao.QuestionDao;
+import jwp.model.Question;
+import jwp.model.User;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpSession;
+import java.sql.SQLException;
+
+@Controller
+@RequestMapping("/qna")
+@RequiredArgsConstructor
+public class QnaController {
+ private final QuestionDao questionDao;
+
+ @GetMapping("/form")
+ public String showQuestionForm(HttpSession session) {
+ if (!UserSessionUtils.isLogined(session)) {
+ return "redirect:/user/loginForm";
+ }
+ return "qna/form";
+ // 화살촉 안티패턴을 피하고 Guard Clause 사용을 위해 비로그인 처리 로직을 위의 if문에
+ }
+
+ @PostMapping("/create")
+ public String createQuestion(
+ @RequestParam("title") String title,
+ @RequestParam("contents") String contents,
+ HttpSession session
+ ) {
+ User sessionUser = (User) session.getAttribute("user");
+ if (sessionUser == null) {
+ return "redirect:/user/loginForm";
+ }
+
+ Question questionToSave = new Question(
+ sessionUser.getUserId(),
+ title,
+ contents
+ );
+
+ questionDao.insert(questionToSave);
+
+ return "redirect:/qna/show?questionId=" + questionToSave.getQuestionId();
+ }
+
+ @GetMapping("/show")
+ public String showQuestion(@RequestParam("questionId") String questionIdParam, Model model) throws SQLException {
+ long questionId = Long.parseLong(questionIdParam);
+
+ Question question = questionDao.findByQuestionId(questionId);
+
+ if (question == null) {
+ System.out.println("해당 ID의 질문을 찾을 수 없습니다: " + questionId);
+ return "redirect:/";
+ }
+
+ model.addAttribute("question", question);
+
+ return "qna/show";
+ }
+}
diff --git a/src/main/java/jwp/controller/UserController.java b/src/main/java/jwp/controller/UserController.java
new file mode 100644
index 0000000..99b816e
--- /dev/null
+++ b/src/main/java/jwp/controller/UserController.java
@@ -0,0 +1,112 @@
+package jwp.controller;
+
+import jwp.dao.QuestionDao;
+import jwp.dao.UserDao;
+import jwp.model.User;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpSession;
+import java.sql.SQLException;
+
+@Controller
+@RequestMapping("/user")
+@RequiredArgsConstructor
+public class UserController {
+ private final UserDao userDao;
+
+ // 회원가입
+ @PostMapping("/signup")
+ public String createUser(@ModelAttribute User user) throws Exception {
+ userDao.insert(user);
+ System.out.println("user 회원가입 완료");
+ return "redirect:/user/list";
+ }
+
+ // 로그인
+ @PostMapping("/login")
+ public String loginUser(
+ @RequestParam("userId") String userId,
+ @RequestParam("password") String password,
+ HttpSession session
+ ) throws Exception
+ {
+ User user = userDao.findByUserId(userId);
+ if (user == null) {
+ System.out.println("아이디를 확인해주세요");
+ return "redirect:/user/loginFailed";
+ }
+ if (user.matchPassword(password)) {
+ session.setAttribute("user", user);
+ System.out.println("로그인 성공");
+ return "redirect:/";
+ } else {
+ System.out.println("비밀번호를 확인해주세요");
+ return "redirect:/user/loginFailed";
+ }
+ }
+
+ // 로그아웃
+ @GetMapping("/logout")
+ public String logoutUser(HttpSession session) {
+ if (session.getAttribute("user") != null) {
+ session.removeAttribute("user");
+ }
+ System.out.println("로그아웃 되었습니다");
+ return "redirect:/";
+ }
+
+ // 유저 전체 목록 조회
+ @GetMapping("/list")
+ public String listUsers(HttpSession session, Model model) throws SQLException {
+ if (UserSessionUtils.isLogined(session)) {
+ model.addAttribute("users", userDao.findAll());
+ return "user/list";
+ }
+ return "redirect:/user/loginForm";
+ }
+
+ // UpdateUserForm
+ @GetMapping("/updateForm")
+ public String showUpdateForm(@RequestParam("userId") String updateUserId, HttpSession session, Model model) throws Exception {
+ User sessionUser = (User) session.getAttribute("user");
+
+ if (sessionUser != null && sessionUser.isSameUser(updateUserId)) {
+ User user = userDao.findByUserId(updateUserId);
+ model.addAttribute("user", user);
+ return "user/updateForm";
+ } else {
+ return "redirect:/";
+ }
+ }
+
+ // Update User
+ @PostMapping("/update")
+ public String updateUser(@ModelAttribute User user, HttpSession session) throws Exception {
+ User sessionUser = (User) session.getAttribute("user");
+
+ if (sessionUser != null && sessionUser.isSameUser(user.getUserId())) {
+ userDao.update(user);
+ session.setAttribute("user", user);
+ return "redirect:/user/list";
+ } else {
+ return "redirect:/";
+ }
+ }
+
+ // 폼(view)을 보여주는 메소드들
+ @GetMapping("/signupForm")
+ public String showSignupForm() {
+ return "user/form";
+ }
+ @GetMapping("/loginForm")
+ public String showLoginForm() {
+ return "user/login";
+ }
+ @GetMapping("/loginFailed")
+ public String showLoginFailed() {
+ return "user/loginFailed";
+ }
+}
diff --git a/src/main/java/jwp/controller/UserSessionUtils.java b/src/main/java/jwp/controller/UserSessionUtils.java
new file mode 100644
index 0000000..5862a4e
--- /dev/null
+++ b/src/main/java/jwp/controller/UserSessionUtils.java
@@ -0,0 +1,21 @@
+package jwp.controller;
+
+import jwp.model.User;
+import javax.servlet.http.HttpSession;
+
+public class UserSessionUtils {
+ public static final String USER_SESSION_KEY = "user";
+
+ public static boolean isLogined(HttpSession session) {
+ Object user = session.getAttribute(USER_SESSION_KEY);
+ return user != null;
+ }
+
+ public static User getUserFromSession(HttpSession session) {
+ Object user = session.getAttribute(USER_SESSION_KEY);
+ if (user == null) {
+ return null;
+ }
+ return (User) user;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/jwp/dao/QuestionDao.java b/src/main/java/jwp/dao/QuestionDao.java
new file mode 100644
index 0000000..8edf82e
--- /dev/null
+++ b/src/main/java/jwp/dao/QuestionDao.java
@@ -0,0 +1,28 @@
+package jwp.dao;
+
+import jwp.model.Question;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Repository;
+
+import javax.persistence.EntityManager;
+import java.sql.SQLException;
+import java.util.List;
+
+@Repository
+@RequiredArgsConstructor
+public class QuestionDao {
+ private final EntityManager em;
+
+ public void insert(Question question) {
+ em.persist(question);
+ }
+
+ public List findAll() throws SQLException {
+ return em.createQuery("select q from Question q", Question.class).getResultList();
+ }
+
+ public Question findByQuestionId(long questionId) throws SQLException {
+ return em.find(Question.class, questionId);
+ }
+
+}
diff --git a/src/main/java/jwp/dao/UserDao.java b/src/main/java/jwp/dao/UserDao.java
new file mode 100644
index 0000000..60354ef
--- /dev/null
+++ b/src/main/java/jwp/dao/UserDao.java
@@ -0,0 +1,34 @@
+package jwp.dao;
+
+import jwp.model.User;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Repository;
+
+import javax.persistence.EntityManager;
+import java.sql.SQLException;
+import java.util.List;
+
+@Repository
+@RequiredArgsConstructor
+public class UserDao {
+
+ private final EntityManager em;
+
+ public void insert(User user) {
+ em.persist(user);
+ }
+
+ public void update(User user) {
+ em.merge(user);
+ }
+
+
+ public List findAll() throws SQLException {
+ return em.createQuery("select u from User u", User.class).getResultList();
+ }
+
+ public User findByUserId(String userId) throws SQLException {
+ return em.find(User.class, userId);
+ }
+
+}
diff --git a/src/main/java/jwp/model/Question.java b/src/main/java/jwp/model/Question.java
new file mode 100644
index 0000000..296e8df
--- /dev/null
+++ b/src/main/java/jwp/model/Question.java
@@ -0,0 +1,62 @@
+package jwp.model;
+
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.CreationTimestamp;
+
+import javax.persistence.*;
+import java.util.Date;
+
+@Entity
+@Table(name = "QUESTIONS")
+@NoArgsConstructor // Lombok에서 제공하는 파라미터 없는 기본 생성자 자동 추가
+public class Question {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long questionId;
+
+ private String writer;
+ private String title;
+ private String contents;
+
+ @CreationTimestamp
+ private Date createdDate;
+
+ @Column(columnDefinition = "int default 0")
+ private int countOfAnswer;
+
+ public Question(long questionId, String writer, String title, String contents, Date createdDate, int countOfAnswer) {
+ this.questionId = questionId;
+ this.writer = writer;
+ this.title = title;
+ this.contents = contents;
+ this.createdDate = createdDate;
+ this.countOfAnswer = countOfAnswer;
+ }
+
+ public Question(String writer, String title, String contents) {
+ this.questionId = 0;
+ this.writer = writer;
+ this.title = title;
+ this.contents = contents;
+ this.createdDate = new Date();
+ this.countOfAnswer = 0;
+ }
+
+ public long getQuestionId() { return questionId; }
+ public String getWriter() { return writer; }
+ public String getTitle() { return title; }
+ public String getContents() { return contents; }
+ public Date getCreatedDate() { return createdDate; }
+ public int getCountOfAnswer() { return countOfAnswer; }
+
+ @Override
+ public String toString() {
+ return "Question{" +
+ "questionId=" + questionId +
+ ", writer='" + writer + '\'' +
+ ", title='" + title + '\'' +
+ ", createdDate=" + createdDate +
+ ", countOfAnswer=" + countOfAnswer +
+ '}';
+ }
+}
diff --git a/src/main/java/jwp/model/User.java b/src/main/java/jwp/model/User.java
index 635bf27..bff28e0 100644
--- a/src/main/java/jwp/model/User.java
+++ b/src/main/java/jwp/model/User.java
@@ -1,7 +1,16 @@
package jwp.model;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "USERS")
+@NoArgsConstructor
public class User {
- private String userId;
+ @Id private String userId;
private String password;
private String name;
private String email;
diff --git a/src/main/java/jwp/support/context/ContextLoaderListener.java b/src/main/java/jwp/support/context/ContextLoaderListener.java
deleted file mode 100644
index e48b948..0000000
--- a/src/main/java/jwp/support/context/ContextLoaderListener.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package jwp.support.context;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.annotation.WebListener;
-import java.util.logging.Logger;
-
-@WebListener
-public class ContextLoaderListener implements ServletContextListener {
- private static final Logger logger = Logger.getLogger(ContextLoaderListener.class.getName());
-
- @Override
- public void contextInitialized(ServletContextEvent sce) {
-// ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
-// populator.addScript(new ClassPathResource("jwp.sql"));
-// ConnectionManager.getDataSource();
-// DatabasePopulatorUtils.execute(populator, ConnectionManager.getDataSource());
-
- logger.info("Completed Load ServletContext!");
- }
-
- @Override
- public void contextDestroyed(ServletContextEvent sce) {
- }
-}
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..c39930f
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,14 @@
+server.port=8080
+# DATABASE PLATFORM
+spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
+
+# DATASOURCE (DB CONNECTION)
+spring.datasource.driver-class-name=org.h2.Driver
+spring.datasource.url=jdbc:h2:~/jwp-basic
+spring.datasource.username=sa
+spring.datasource.password=
+spring.sql.init.mode=always
+spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
+
+spring.mvc.view.prefix=/WEB-INF/views/
+spring.mvc.view.suffix=.jsp
\ No newline at end of file
diff --git a/webapp/css/styles.css b/src/main/resources/static/css/styles.css
similarity index 100%
rename from webapp/css/styles.css
rename to src/main/resources/static/css/styles.css
diff --git a/webapp/css/styles2.css b/src/main/resources/static/css/styles2.css
similarity index 100%
rename from webapp/css/styles2.css
rename to src/main/resources/static/css/styles2.css
diff --git a/webapp/favicon.ico b/src/main/resources/static/favicon.ico
similarity index 100%
rename from webapp/favicon.ico
rename to src/main/resources/static/favicon.ico
diff --git a/webapp/img/KUIT.png b/src/main/resources/static/img/KUIT.png
similarity index 100%
rename from webapp/img/KUIT.png
rename to src/main/resources/static/img/KUIT.png
diff --git a/webapp/img/picture.jpeg b/src/main/resources/static/img/picture.jpeg
similarity index 100%
rename from webapp/img/picture.jpeg
rename to src/main/resources/static/img/picture.jpeg
diff --git a/webapp/js/scripts.js b/src/main/resources/static/js/scripts.js
similarity index 100%
rename from webapp/js/scripts.js
rename to src/main/resources/static/js/scripts.js
diff --git a/webapp/WEB-INF/.gitignore b/src/main/webapp/WEB-INF/.gitignore
similarity index 100%
rename from webapp/WEB-INF/.gitignore
rename to src/main/webapp/WEB-INF/.gitignore
diff --git a/webapp/home.jsp b/src/main/webapp/WEB-INF/views/home.jsp
similarity index 98%
rename from webapp/home.jsp
rename to src/main/webapp/WEB-INF/views/home.jsp
index ac8aec8..958d673 100644
--- a/webapp/home.jsp
+++ b/src/main/webapp/WEB-INF/views/home.jsp
@@ -75,6 +75,6 @@
-
+