66日目:Spring+MyBasis(メールの送信、IDの使用の確認、IDの検索、会員登録サービス、Propertyの直接作成)
2022.02.17.Thur.
復習する
共通
ちょっと違うspringboot start
セキュリティレベルの低いアプリケーションを有効にする方法
Googleアカウント管理→セキュリティ→セキュリティレベルの低いアプリケーションの使用を許可
sql.txtの作成
tableを作成し、cmdウィンドウにコピーして貼り付けます.
設定のキャプチャとファイルの追加
スナップの設定
pom.xml
mapper.xmlの変更
application.properties
ファイルの追加
log4jdbc.log4j2.properties
logback-spring.xml
DIメソッド
注入作成者(@RequiredArgConstructor)、新しいデータの注入、フィールドの注入(@Autowired)
どのようなDIが良いですか?
ロムフォードを利用して生成者に注入する.
順序どおりに勤務する.
com.example.demo
SecurityConfig.java
package com.example.demo;
import org.springframework.beans.factory.annotation.*;
import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.method.configuration.*;
import org.springframework.security.config.annotation.web.builders.*;
import org.springframework.security.config.annotation.web.configuration.*;
import org.springframework.security.crypto.password.*;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests().antMatchers("/**").permitAll();
}
}
@Autowired
private PasswordEncoder passwordEncoder;
http:WebSecurityConfigurator Adapterが提供する構成(HTTP)のプリファレンス
Zboard6Appication.java
package com.example.demo;
import org.mybatis.spring.annotation.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@MapperScan("com.example.demo.dao")
@SpringBootApplication
public class Zboard6Application {
public static void main(String[] args) {
SpringApplication.run(Zboard6Application.class, args);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
com.example.demo.controller
MemberController.java
package com.example.demo.controller;
import java.lang.reflect.Member;
import java.time.LocalDate;
import org.springframework.http.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import com.example.demo.controller.editor.DatePropertyEditor;
import com.example.demo.service.MemberService;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Controller
public class MemberController {
private final MemberService service;
// 사용자 입력을 가지고 command 객체를 생성하는 작업을 스프링에서 binding한다고 한다.
@InitBinder
public void init(WebDataBinder wdb) {
// LocalDate로 변환할 에디터를 등록한다면
// wdb.registerCustomEditor(LocalDate,class, new DatePropertyEditor()); → 모든 LocalDate에 대해 동작
// wdb.registerCustomEditor(LocalDate,class, "birthday", new DatePropertyEditor()); → birthday 필드에 대해 동작
wdb.registerCustomEditor(LocalDate.class, "birthday", new DatePropertyEditor());
}
@GetMapping("/member/join")
public void join() {
}
@PostMapping("/member/join")
public String join(Member member) {
// 아이디, 비번, 이메일, 이름, 생일, 레벨을 사용자가 입력한다(레벨은 연습용)
// 문자열 "15"를 입력하면 스프링은 String, Integer, Double로 변환할 수 있다
// 스프링에서 입력할 때 문자열 변환을 담당하는 표준은 PropertyEditor
// 스프링은 문자열, 정수, 실수등의 PropertyEditor를 제공한다
// 그런데 문자열을 날짜로 또는 문자열을 enum으로 변환하는 PropertyEditor는 제공하지 않는다 errorcode400→ 우리가 만들어서 등록하면 된다
// 우선 "2020-01-10"을 LocalDate로 바꾸는 DatePropertyEditor를 만들자
service.join(member);
return "redirect:/member/login";
}
}
com.example.demo.controller.editor
DatePropertyEditor.JAva-Propertyの直接作成
package com.example.demo.controller.editor;
import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
public class DatePropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
// setAs ctrl+enter
// text 파라미터 : 사용자가 입력한 문자열. 지금같은 경우 "2020-11-20"
String str[] = text.split("-"); // ["2020", "11", "20"]
Integer year = Integer.parseInt(str[0]);
Integer month = Integer.parseInt(str[1]);
Integer day = Integer.parseInt(str[2]);
LocalDate date = LocalDate.of(year, month, day);
// 마지막으로 setValue 사용
setValue(date);
}
}
com.example.demo.dao
MemberDao.java
package com.example.demo.dao;
import java.util.Optional;
import org.apache.ibatis.annotations.*;
import com.example.demo.entity.*;
@Mapper
public interface MemberDao {
public Integer save(Member member);
// mybatis 3.5부터 Optional 리턴을 지원
public Optional<Member> findById(String username);
// select * from
public Optional<Member> findByEmail(String email);
// select username from
// public String findUsernameByEmail(String email);
public Integer update(Member member);
public Integer deleteById(String username);
public Boolean existsById(String username);
}
com.example.demo.entity
Level.java
package com.example.demo.entity;
public enum Level {
BRONZE, SILVER, GOLD;
}
Member.javapackage com.example.demo.entity;
import java.time.*;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Member {
private String username;
private String password;
private String irum;
private String email;
private LocalDate birthday;
private LocalDate joinday;
private Boolean enabled;
private String authority;
private String checkcode;
private Integer count;
private Level levels;
}
com.example.demo.service
MemberService.java
package com.example.demo.service;
import java.lang.reflect.Member;
import java.util.Optional;
import javax.mail.*;
import javax.mail.internet.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.mail.javamail.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import com.example.demo.dao.MemberDao;
import com.example.demo.entity.Level;
import lombok.RequiredArgsConstructor;
// DI하는 방법 : 생성자 주입(@RequiredArgsConstructor), 새터 주입, 필드 주입(@Autowired) → 어떤 DI가 바람직할까? → 롬복을 이용해 생성자 주입을 하자
@RequiredArgsConstructor
@Service
public class MemberService {
private final JavaMailSender javaMailSender;
private final MemberDao memberDao;
private final PasswordEncoder passwordEncoder;
// 메일 보내는 메소드
public void sendMail(String from, String to, String title, String content) throws MessagingException {
// MIME : 이메일의 형식 -> 파일의 형식. 파일의 종류를 MIME type
// html에서 엑셀 문서를 클릭하면 application/excel이라는 MIME 타입이 내 브라우저로 전달된다
// 브라우저는 윈도우에서 엑셀을 찾아서 있으면 엑셀을 실행 -> 엑셀 문서가 열린단
// 엑셀이 없으면 즉 application/excel이란 마임 타입이 알 수 없는 타입이라면 다운로드
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, false, "utf-8");
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(title);
helper.setText(content, true);
javaMailSender.send(message);;
}
// 아이디 사용여부 확인
public Boolean idAvailableCheck(String username) {
// existsById는 null이 발생하지 않는다
return !memberDao.existsById(username);
}
// 아이디 찾기
public String findId(String email) {
// return memberDao.findByEmail(email).getUsername(); → 사용자가 없는 경우 NPE(null pointer exception) 발생할 수 있다
// NPE이 발생하는 지 여부를 판단을 누가 판단할까 → DAO 작성자
// 메소드를 만드는 사람이 Optional 클래스를 이용해 메소드 사용자에게 NPE여부를 가르쳐주자
// Optional이라는 포장상자안에 Member가 들어있다
// Optional을 꺼내는 메소드는 get() → null인 경우 NoSuchElememtException 발생
// memberDao.findByEmail(email).get();
Optional<Member> result = memberDao.findByEmail(email);
if(result.isPresent()==true)
return result.get().getUsername();
return "아이디를 찾지 못했습니다";
}
// 회원가입
public void join(Member member) {
member.setPassword(passwordEncoder.encode(member.getPassword()));
System.out.println(member);
// member.setLevels(Level.BRONZE);
// memberDao.save(member);
}
}
Test
MemberDaoTest.java, MemberServiceTest.java
ファイルをsvnにインポート(混同...)
Reference
この問題について(66日目:Spring+MyBasis(メールの送信、IDの使用の確認、IDの検索、会員登録サービス、Propertyの直接作成)), 我々は、より多くの情報をここで見つけました https://velog.io/@wontwopunch/66일-Spring-email-Serviceテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol