# Spring Boot
## [spring initializr](https://start.spring.io/)
### [IOC](https://en.wikipedia.org/wiki/Inversion_of_control)
- [DI (Dependency Injection)](https://www.educative.io/answers/what-is-dependency-injection-in-java)
- [ref 2](https://medium.com/groupon-eng/dependency-injection-in-java-9e9438aa55ae)
### controller / service / repository
```java
@RestController
@RequestMapping(value = "/rest/employee")
public class EmployeeController {
@Autowired
@Qualifier("employeeService")
private IEmployeeService employeeService;
}
```
### [AOP](https://openhome.cc/Gossip/SpringGossip/AOPConcept.html)
- design pattern [proxy](https://refactoring.guru/design-patterns/proxy)


```java
@Aspect
@Component
public class ServiceAspect {
@Pointcut("execution(* com.demo.service.*.*(..))")
public void serviceMethods() {
// only use for AOP pointcut
}
@Before(value = "serviceMethods()")
public void serviceBefore(JoinPoint joinPoint) { //......
}
}
```
### Architecture
- MVC
- 3-tier
### RESTful API
### ORM 選讀
- [JPA](https://www.vogella.com/tutorials/JavaPersistenceAPI/article.html)
- [sample](https://bitbucket.org/re102162189/springboot_jpa_mybatis_security/src/master/src/main/java/com/demo/service/SkillService.java)
```java
@Service
public class SkillService implements ISkillService {
@Autowired
private SkillRepository skillRepository;
@Override
public Optional<Skill> findByIdJpa(long id) {
return skillRepository.findById(id);
}
@Override
public Optional<Skill> findByIdJpaQuery(long id) {
return skillRepository.findByIdUsingQuery(id);
}
}
public interface SkillRepository extends JpaRepository<Skill, Long> {
@Query("SELECT s FROM Skill s JOIN FETCH s.employees e WHERE s.id = :id")
Optional<Skill> findByIdUsingQuery(@Param("id") long id);
}
```
### MyBatis / JDBCTemplate
- [sample](https://bitbucket.org/re102162189/springboot_jpa_mybatis_security/src/master/src/main/java/com/demo/jdbc/dao/SkillJdbcDao.java)
```java
@Repository
public class SkillJdbcDao {
private static final String SELECT = //
"SELECT s.id AS id, s.name AS name, e.id AS e_id, e.name AS e_name" +
" FROM skill s" +
" INNER JOIN employee_skill es ON s.id=es.skill_id" +
" INNER JOIN employee e ON e.id=es.employee_id" +
" WHERE s.id=:id";
private static final String UPDATE =
"UPDATE skill SET name=:name WHERE id=:id";
private static final String INSERT =
"INSERT INTO skill (name) VALUES (:name)";
private static final String DELETE =
"DELETE FROM skill WHERE id=:id";
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public Optional<Skill> findById(long id) {
return namedParameterJdbcTemplate.queryForObject(SELECT,
new MapSqlParameterSource("id", id), new SkillRowMapper());
}
public int insert(Skill skill) {
return namedParameterJdbcTemplate.update(INSERT,
new BeanPropertySqlParameterSource(skill));
}
public int update(Skill skill) {
return namedParameterJdbcTemplate.update(UPDATE,
new BeanPropertySqlParameterSource(skill));
}
public int delete(long id) {
return namedParameterJdbcTemplate.update(DELETE,
new MapSqlParameterSource("id", id));
}
}
```
### Security
- [CSRF](https://blog.techbridge.cc/2017/02/25/csrf-introduction/)
- [CORS](https://shubo.io/what-is-cors/)
- [sample](https://bitbucket.org/re102162189/springboot_jpa_mybatis_security/src/master/src/main/java/com/demo/config/SecurityConfig.java)
```java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private Realm realm;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
String readUsername = realm.getReadUsername();
String readPassword = encoder().encode(realm.getReadPassword());
String readRole = realm.getReadRole();
String writeUsername = realm.getWriteUsername();
String writePassword = encoder().encode(realm.getWritePassword());
String writeRole = realm.getWriteRole();
UserDetails readUser = User.builder()
.username(readUsername)
.password(readPassword)
.roles(readRole)
.build();
UserDetails writeUser = User.builder()
.username(writeUsername)
.password(writePassword)
.roles(writeRole, readRole)
.build();
auth.inMemoryAuthentication()
.withUser(readUser)
.withUser(writeUser);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
String readRole = realm.getReadRole();
String writeRole = realm.getWriteRole();
http.httpBasic().and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/rest/**").hasAnyRole(readRole, writeRole)
.antMatchers(HttpMethod.POST, "/rest/**").hasRole(writeRole)
.antMatchers(HttpMethod.PUT, "/rest/**").hasRole(writeRole)
.antMatchers(HttpMethod.DELETE, "/rest/**").hasRole(writeRole)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.cors().disable();
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}
```
### Sample Code
- [git](https://bitbucket.org/re102162189/springboot_jpa_mybatis_security/)