728x90

에러메세지

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)

 

사용 프로그램 & 버젼, filePath 등 환경

amazon linux 2023

인스턴스 유형 : t2.micro (프리티어)

 

발생날짜

2023년 12월 4일

 

상황

어느날 AWS EC2 접속 후 MySQL에 접속하려고 로그인하니 갑자기 에러 발생하면서 로그인이 안됨

 

에러 원인

보통 이 문제는 RPM으로 MySQL을 설치한 경우 생기는 에러라고 함

※mysql.sock파일은 rm 명령어로 삭제해도 다시 생겨 근본적인 해결책은 X

rm -rf /var/lib/mysql/mysql.sock

 

해결 방법

MySQL을 root 계정으로 설치했다면 mysql.sock의 소유권이 없기에 chmod와 chown 명령어를 이용해 권한을 바꿔주면 해결가능

 

코드

service mysqld stop           // mysql 프로세스 정지
chmod 755 -R /var/lib/mysql   // 권한 변경 : 지정 디렉토리의 하위포함 권한 전체 변경
chown mysql:mysql -R /var/lib/mysql // 소유자 변경 : mysql을 mysql이라는 소유자로 변경
service mysqld start          // mysql 프로세스 기동

 

728x90
반응형
728x90

에러메세지

The bean 'userLoanHistoryRepository', defined in com.group.libraryapp.prac3.repository.UserLoanHistoryRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration, could not be registered. A bean with that name has already been defined in com.group.libraryapp.prac2.domain.user.loanhistory.UserLoanHistoryRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration and overriding is disabled.

 

사용 프로그램 & 버젼, filePath 등 환경

java11

springboot 2.7

spring-data-jpa

 

발생날짜

December 3, 2023

 

상황

코드 연습용 모듈에 반복적인 클래스 생성으로 빈 충돌한 상황

 

에러 원인

같은 이름 다른 패키지경로의 클래스들 때문에 빈생성 등록할 때 충돌남

 

해결 방법

extends JpaRepository하면 굳이 @Repository에서 빈등록 안해도 자동으로 빈등록을 해주며 이렇게 빈등록된 게 다른 곳에서 중복된 빈이름과 충돌한 것

 

코드

public interface BookRepository extends JpaRepository<Book, Long> {
728x90
반응형
728x90

 

세션 영역에 있는 관리자 로그인 정보 중에 id만 가져와서

admin 테이블로 casting하고 다시 보드 테이블에 넣어주어 이를 공지사항 쓰기할 때

고정적으로 작성자에 보여주는걸로 코드 수정 및 기능 추가

 

	@RequestMapping("adminNoticeWriteView.ad")
	public String adminNoticeWriteView() {
		return "adminNoticeWriteView";
	}

 

	@RequestMapping("adminNoticeWriteView.ad")
	public String adminNoticeWriteView(@ModelAttribute Board b, Model model, HttpSession session) {
		
		String adId = ((Admin)session.getAttribute("adminUser")).getId();
		b.setAdminId(adId);
		model.addAttribute("b",b);
		
		return "adminNoticeWriteView";
	}

 

728x90
반응형
728x90

 

인터셉터란?

컨트롤러(Controller)의 '핸들러(Handler)'를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할수 있는 일종의 필터

interceptor 란 단어는 '낚아채다'라는 의미.

해당 단어의 의미와 같이 사용자 요청에 의해 서버에 들어온

Request 객체를 컨트롤러의 핸들러(사용자가 요청한 url에 따라 실행되어야 할 메서드, 이하 핸들러)로

도달하기 전에 낚아채서 개발자가 원하는 추가적인 작업을 한후 핸들러로 보낼수 있도록 해주는것이 인터셉터

 

사용 목적

개발자는 특정 Controller의 핸들러가 실행되기 전이나 후에 추가적인 작업을 원할때 Interceptor를 사용

(추가적인 작업으로는 로그인체크, 권한 체크 등이 있다.)

 

적용해야할 핸들러가 수천개가 된다면 어떻게될까?

크게 두가지 문제가 생긴다.

1) 메모리 낭비, 서버의 부하 증가

    - 적용해야할 핸들러만 수만큼 세션체크 코드를 작성함으로써 반복되는 코드들이 매우 많아지기 때문

2) 코드의 누락

 

 

 

(Interceptor, AOP도 요청을 가로채는 녀석)

 

인터셉터가 들어갈 수 있는 시점 3가지

(인터셉터가 사용할 수 있는 메소드 3가지)

  1. preHandle()
  2. postHandle()
  3. afterCompletion()

인터셉터 수행한다 = 인터셉터가 가로챈다

 

  1. preHandle() : Servlet이 Controller를 호출하기 전에 수행
  2. postHandle() : Controller에서 Servlet으로 리턴되는 순간에 수행
  3. afterCompletion() : 최종 결과를 생성하는 일을 포함한 모든 작업이 완료 된 후

 

최종결과란 뷰까지 다 처리한 상태를 의미

(모든 View에서 최종 결과를 생성하는 일을 포함한 모든 작업이 완료된 후에 실행)

 

Q.뷰까지 다 처리됬다는게 클라이언트에 리스폰스까지 끝난거를 의미한건가요?

A.응답이 다 끝났으니까 그때 인터셉터를 실행한다는 의미

 

※ 필터(Filter)와 인터셉터(Interceptor)의 사용처 차이

필터 인코딩처리에 많이 사용

인터셉터 : 로그인처리에 많이 사용

장바구니 눌렀다가 로그인이 안되어있으면 로그인으로 가는게 인터셉터

이거는 프리핸들러로 구분될 것임. 장바구니 쓸려는 컨트롤러 수행전에 해야하는 것이기 때문

  • 적용되는 위치 차이
  • 필터 : 자바
  • 인터셉터 : 스프링
728x90
반응형
728x90

 

 

▶ log

로그 기록의 로그이기도 함

 

목적

기록을 남기고자 할 때 사용

1)콘솔에 찍는 용도

    - 프린트메소드 사용하는게 시스템적 관점에서 성능저하가 좀 된다고함

    - 많이 찍어야한다고 하면 로그를 많이 사용

2)db에 저장하는 용도

3)파일에 저장하는 용도

    - 파일에 가장 많이 사용

    - 파일에 먼저 저장하고 db에 저장하는 경우 많음. db는 용량 한계가 있는 경우가 많기에

 

콘솔에 찍히는 기록도 log

 

장점

1)파일, DB 등에 저장 가능

    - 파일은 stream 통해 저장가능

2)로그 파악이 쉬워 문제 해결이 용이

3)빠르고 효율적인 디버깅 가능

 

단점

1)코드 양 증가

로그를 하기 위한 설정 코드들이 길다

    - 로그를 사용하기 위한 설정정보들을 가지고 와야하는데, 단순하게 콘솔 넣는거만 생각해보더라도 print만 불러오면 되는데 로그를 하기위한 설정 코드들이 꽤 길어서 전체적인 코드양이 꽤 많이 늘어남

2)개발 중간에 로그 코드를 넣기가 어려움

    - 전체적으로 코드양 증가 → 개발 중간에 로그 코드를 넣기가 어려움

3)심하게 많이 생성되는 로그는 혼란을 야기하고, 로그 때문에 성능에도 영향이 갈 수 있음

    - 문제 해결을 위해 로그를 너무 많이 넣어두면 양이 많아지기 때문

 

로그에 관한 것들

콘솔에 찍히는 기록

HomeController

logger :인터페이스(Interface)

 

 

로그 설정 파일

경로 : src/main/resources

log4j.xml

 

log4j.xml 안의 태그들

1)Appenders

2)Application Loggers

3)Root Logger

 

1)Appenders

전달 받은 로그를 어디에 출력할지 결정

 

ConsoleAppender : 로그를 콘솔에 출력하기 위한 어펜더

JDBCAppender : 로그를 db에 출력하기 위한 어펜더

FileAppender : 로그를 파일에 출력하기 위한 어펜더

    - 단점 : 지정 파일에 로그가 계속 남아 크기가 지나치게 커지고 지속적인 로그 관리가 불가능하다는 단점

RollingFileAppender : 파일어펜더를 보완하는 어펜더

    - 일정 조건 후에 기존 파일을 백업 파일로 바꾸고 다시 처음부터 시작

    - 백업파일이 1-10까지 기록했으면 다음 파일은 11-20까지 기록하는 식

ex)

1-100까지 포문 돌리는 중. 새로 시작하는 지점

1-10까지 담기고 백업파일로

11-20 담기고 백업파일로 담기고

ex. DailyRollingFileAppender : 하루마다 백업

 

<appender>

<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
	<param name="Target" value="System.out" />
	<layout class="org.apache.log4j.PatternLayout">
		<param name="ConversionPattern" value="%-5p: %c - %m%n" />
	</layout>
</appender>

name 어디다 넣을것인지 지정

layout 형식

 

<layout> : 로그를 어떤 형식으로 출력할 것인지 결정

layout 종류

1)DateLayout

2)HTMLLayout

3)PatternLayout : 디버깅에 가장 적합

4)SimpleLayout

5)XMLLayout

<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.**PatternLayout**">
			<param name="ConversionPattern" value="%-5p: %c - %m%n" />
		</layout>
	</appender>

 

<layout> value속성

  • %p : debug, info, warn, error, fatal 등의 priority
  • %m : 로그 내용 출력
  • %d : 로깅 이벤트가 발생한 시간 출력(프로그램 속도를 느리게 할 수 있음)
  •   - 포맷을 %d{HH:mm:ss, SSS}와 같은 형태로 사용하며 SimpleDateFormat에 따른 포매팅을 하면 됨
  • %t : 로깅 이벤트가 발생된 스레드 이름 출력
  • %% : % 출력
  • %n : 개행문자 출력
  • %c : package(카테고리) 출력
  • %c{n} : n(숫자)만큼의 package 를 하단부터 역으로 출력
  • %C : 호출자의 클래스명 출력 ( 클래스가 대문자로 시작하니 c도 대문자C)
  • %f : 로깅이 발생한 프로그램 파일명 출력
  • %l : 로깅이 발생한 caller의 정보 출력
  • %L : 로깅이 발생한 caller의 라인수 출력
  • %M : 로깅이 발생한 method이름 출력
  • %r : 애플리케이션 시작 이후부터 로깅이 발생한 시점의 시간(밀리세컨) 출력

 

<layout> 아래 <param value=””>의 해석 value=”%-5p” : 왼쪽정렬. 그냥5p면 오른쪽정렬

콘솔 어펜더에서 지정하고 있는 패턴이 뭐를 가지고 이용 했는지

내 로그가 어떻게 찍혔는지를 한번 더 확인 해보라

 

2)Application Loggers

등록된 로그들을 받아주는 역할

name속성에 등록된 영역들을 다 받아서 관리하겠다

<logger name="**com.kh.Spring**">
		<level value="info" />
</logger>

등록된 로그들을 받아주는 역할

     DEBUG < INFO < WARN < ERROR< FATAL        (오른쪽으로 갈 수록 심각한 에러)

설정한 level 이상만 출력

      ex) level info라고 지정하면 debug는 안보임

  • fatal : 아주 심각한 에러발생
  • error : 어떤 요청 처리 중 문제 발생
  • warn : 프로그램 실행에는 문제 없지만 향후 시스템 에러의 원인이 될 수 있는 경고성 메세지
  • info : 상태 변경과 같은 정보성 메세지
  • debug : 개발 시 디버그 용도로 사용하는 메세지
  • trace : debug가 너무 광범위한 것들 해결하기 위해 디버그보다 좀 더 상세한 이벤트를 나타냄. 경로추적에서 많이씀

 

 

3)Root Logger

모든 자식 2번 <logger>들의 로깅 출력이 3번<root> root logger를 통해 일어남

2번의 모든 로거들은 실행이 되면 3번Root Logger로 찾아옴

 

 

728x90
반응형
728x90

 

기능이 실패했을 경우 예외처리

 <Checked Exception & Unchecked Exception>

  Checked Exception : 예외처리가 필수
  Unchecked Exception : 예외처리 선택

 Unchecked Exception의 조상 Runtime Exception
 Checked Exception의 조상은 Exception

예외 처리할 필요가 없게 extends를 Runtime Exception로 변경

package com.kh.Spring.member.model.exception;

public class MemberException extends RuntimeException {

	// Checked Exception & Unchecked Exception
	// 		Checked Exception : 예외처리가 필수
	// 		Unchecked Exception : 예외처리 선택
	
	// Unchecked Exception의 조상 Runtime Exception
	// Checked Exception의 조상은 Exception
	
	// 예외 처리할 필요가 없게 extends를 Runtime Exception로 변경
	
	public MemberException() {}
	public MemberException(String msg) {
		super(msg);
	}
	
}
728x90
반응형
728x90

 

초기세팅하면서 어떻게 스프링 프레임워크를 사용해야되는지 연습해보았다

 

root-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->

<!-- Basic DataSource 등록 -->	
	<!-- MVN Repository에서 commons-dbcp 검색해서 메이븐에 추가해야 사용가능 -->
	<!-- 이 DataSource를  SqlSession bean, DataSourceTransactionManager가 ref해서 사용하는 구조 -->
	<bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource" destroy-method="close"> 
	<!-- destroy-method : 닫아주는 메소드로 close를 사용하겠다  -->
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
		<property name="username" value="Spring"/>
		<property name="password" value="Spring"/>
	</bean>

	 
<!-- SqlSession 빈(bean) 등록 -->
	 <bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- mybatis라이브러리랑 mybatis Spring라이브러리를 미리 받아서 에러가 안드는 것 -->
	 	<property name="dataSource" ref="dataSource"/> <!-- 참고할거임. 데이터 소스를 참고할 것. id로 썼던 데이터소스를 의미  -->
	 	<!-- 마이바티스 컨피그에서 설정 정보를 설정했었음 -->
	 	<!-- 마이바티스 컨피그.xml파일을 읽어와야함 --> 
	 	<property name="configLocation" value="classpath:mybatis-config.xml"/>  
	 	<!-- classpath는 src/main/resource폴더를 의미함 --><!-- mybatis-config.xml 안만들었으니 만들러 ㄱㄱ -->
	 </bean> 
	 
<!-- Template 생성 -->
	<!-- SqlSessionFactoryBean를 ref함 -->
	 <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
	 	<constructor-arg ref="sqlSession"/>  <!-- 매개변수 있는 생성자. 위의 1번 방법에 있는 그것-->
	 </bean>
 <!-- transactionManager : 트랜잭션 집어넣을 수 있게 -->
	 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	 	<property name="dataSource" ref="dataSource"/>
	 </bean>
	 
 <!-- 파일업로드 : multipartResolver -->
	 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	 	<property name="maxUploadSize" value="100000000"/>	<!-- value : 용량 정하기 -->
		<property name="maxInMemorySize" value="100000000"/>
	 </bean>
	 
	 
	 	 		
</beans>

 

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="prac.prac.practice" />
	
	
	
</beans:beans>

 

컨트롤러

package prac.prac.practice.board.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import prac.prac.practice.board.model.service.BoardService;

@Controller
public class BoardController {

	
	@Autowired
	private BoardService boardService;
	
}

서비스/서비스Impl

package prac.prac.practice.board.model.service;


public interface BoardService {

}

///////////////////////////////////////////////

package prac.prac.practice.board.model.service;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import prac.prac.practice.board.model.dao.BoardDAO;

@Service("boardService")
public class BoardServiceImpl implements BoardService {

	@Autowired
	private BoardDAO boardDAO;
	
	@Autowired
	private SqlSessionTemplate SqlSession;

}

 

DAO

package prac.prac.practice.board.model.dao;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;

@Repository("boardDAO")
public class BoardDAO {

	
	
}

 

 

728x90
반응형
728x90

 

 

${ bdelete }

84번째 라인 ${ bdelete } 태그가 73번째 라인 var=”bdelete”를 가져다 쓰는거고 bdelete의 value속성은 url을 담고있음

삭제하기 버튼을 누르면 84번째 라인 ${ bdelete } 가 실행되고 var=”bdelete”가 호출되고 var=”bdelete”와 이어져있는 url인 bdelete.bo가 연결된 콘트롤러로 연결됨.

이때 74번째 라인 <c:param> 안에 pk역할을 하는 name=”bId”를 콘트롤러에서 데이터를 받게되면 ${ board.boardId } 를 받는데 db의 boardId 컬럼은 게시글 번호이므로 1,2,3,4 이런식으로 int값이 최종적으로 컨트롤러에 들어가게된다

삭제하기 버튼 누르면 bdelete쪽으로 넘길 때

<c:param name="bId" value="${ board.boardId }"/> 이부분을 가지고 넘김

 

@RequestMapping("bdelete.bo")
public String deleteBoard(@RequestParam("bId") int bId, 
						  @RequestParam("renameFileName") String renameFileName, HttpServletRequest request) {
	// boardDetailView
	// 어디서 접근해서 삭제할지도 지정해야하니 HttpServletRequest도 추가

	if(!renameFileName.equals("")) { // renameFileName이 비어있지 않다면
		deleteFile(renameFileName, request); // renameFileName을 넘겨준다, 어디서 삭제할 것인가:request
	}
	int result = bService.deleteBoard(bId);

 

728x90
반응형
728x90

 

이클립스or STS와 Maven(메이븐) 연결

 

window- Preferences - Maven - User Settings

User settings를 참고해서 local respository에서 가져다 씀

 

 

User Settings에서 Browse 눌러서 Maven의 setting.xml을 지정하면 자동으로 setting.xml에서 지정한 경로로 자동으로 local Repository가 바뀐다

메이븐 설정 파일에서 미리 라이브러리 세팅 폴더를 설정해둔 경로로 자동으로 변경된 것

 

Maven(메이븐)의 라이브러리 저장 폴더 변경은 아래의 링크에

https://rise-up.tistory.com/506

728x90
반응형
728x90

 

 

우클릭 new에서 나오는 옵션들 shortcut 설정

window - Perspective - Customize Perspective

 

 

우클릭new 해서 shortcut 설정 변경 전까지는 untitled Text File까지 떴으나

이 아래 항목들 추가하고나서 더 뜨는 모습을 볼 수 있다

 

 

728x90
반응형

+ Recent posts