ํฐ์คํ ๋ฆฌ ๋ทฐ
[spring] ํด๋ก ์ฝ๋ฉ02 User - Model, Repository, Mapper, Test, Service, Controller
yeahajeong 2019. 11. 29. 20:44๊ธฐ๋ณธ์ ์ผ๋ก ์ธ์คํ๊ทธ๋จ์ ๋ก๊ทธ์ธ์ ํด์ผ ๋ชจ๋ ์๋น์ค๋ฅผ ์ด์ฉํ ์ ์๋ค. ๊ทธ๋์ ๋จผ์ ํ์(์ ์ )์ ๊ดํ ๋ก์ง๋ถํฐ ์์ฑํด๋ณด๊ฒ ๋ค.
Model
UsersVO ํ์ ๋ชจ๋ธ ์์ฑ
package com.hastagram.myapp.users.model;
import java.util.Date;
import org.springframework.web.multipart.MultipartFile;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class UsersVO {
private int userNo; //ํ์ ๋ฒํธ
private String email; //ํ์ ์ด๋ฉ์ผ
private String id; //ํ์ ์์ด๋
private String pw; //ํจ์ค์๋
private String name; //ํ์ ์ด๋ฆ
private String intro; //์๊ฐ๋ง
private String phone; //์ ํ๋ฒํธ
private Date regDate; //๋ฑ๋ก๋ ์ง
//ํด๋ผ์ด์ธํธ ์ธก์์ ๋์ด์จ ํ์ผ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ํ๋ผ๋ฏธํฐ ์ฝ๊ธฐ์ฉ
private MultipartFile file;
//ํ๋กํ ํ์ผ์ ์ํ ํ๋
private int userImgNo;
private String profileName; //ํ์ผ ์ด๋ฆ
private long profileSize; //ํ์ผ ํฌ๊ธฐ
private String profileContentType; //ํ์ผ ํ์
}
ํ์์์ ํ์ํ ๊ฒ ๊ฐ์ ํ๋๋ค์ ์์ฑํ์๋ค.
UserImgsVO ํ์ ํ๋กํ ์ฌ์ง ๋ชจ๋ธ ์์ฑ
package com.hastagram.myapp.users.model;
import org.springframework.web.multipart.MultipartFile;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@ToString(exclude = "profileData")
public class UserImgsVO {
private int userImgNo;
private int userNo;
private String profileName;
private long profileSize;
private String profileContentType;
private byte[] profileData;
private MultipartFile file;
}
ํ๋กํ ์ฌ์ง ํ์ ๋ชจ๋ธ์ ํ๋กํ ์ฌ์ง ์ ๋ณด๋ ๊ฐ์ด ๋ด์๊น ์๊ฐํ์ง๋ง ํ๋กํ ์ฌ์ง์ด ์๋ ํ์์ด ์์ ์ ์์ผ๋ ํ์ ํ๋กํ ์ฌ์ง ๋ชจ๋ธ์ ๋ฐ๋ก ๋ง๋ค์ด ์ฃผ์๋ค.
LoginVO ๋ก๊ทธ์ธ ์๋ํ๋ ํ์ ์ ๋ณด ๋ด์๋๋ ๋ชจ๋ธ
package com.hastagram.myapp.users.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@ToString
public class LoginVO {
private String email; //๋ก๊ทธ์ธ ์๋ ์ด๋ฉ์ผ
private String pw; //๋ก๊ทธ์ธ ์๋ ๋น๋ฐ๋ฒํธ
}
Lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ -> setter, getter, toString ๋ฑ ์๋์ผ๋ก ์์ฑํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ํ๋๋ง ์ถ๊ฐํด๋์ผ๋ฉด ๋๋ค. pom.xml์ lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ค์ด ๋ฐ์์ ์ฌ์ฉ
<!-- lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ค์ด๋ก๋ -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
Repository
IUsersDAO
package com.hastagram.myapp.users.repository;
import com.hastagram.myapp.users.model.LoginVO;
import com.hastagram.myapp.users.model.UserImgsVO;
import com.hastagram.myapp.users.model.UsersVO;
public interface IUsersDAO {
/*************** ํ์๊ฐ์
๋ก์ง ***************/
//ํ์ ๊ฐ์
์ฒ๋ฆฌ
void register(UsersVO user) throws Exception;
//์ด๋ฉ์ผ ์ค๋ณตํ์ธ ์ฒ๋ฆฌ
int isDuplicateEmail(String email) throws Exception;
//์์ด๋ ์ค๋ณตํ์ธ ์ฒ๋ฆฌ
int isDuplicateId(String id) throws Exception;
/*************** ๋ก๊ทธ์ธ ๋ก์ง ***************/
//๋ก๊ทธ์ธ ์๋ ํ์์ ๋ณด ์กฐํ ์ฒ๋ฆฌ
UsersVO login(LoginVO login) throws Exception;
/*************** ํ์ ์ ๋ณด ๋ก์ง ***************/
//ํ์ ์ ๋ณด ์์
void modifyInfo(UsersVO user) throws Exception;
//์ฒจ๋ถํ์ผ์ DB์์ ๋ถ๋ฌ์ค๊ธฐ
UserImgsVO getProfile(int userNo) throws Exception;
//ํ๋กํ ์ฌ์ง ๋ฑ๋ก
void insertUserImg(UserImgsVO file) throws Exception;
//์์ด๋๋ก ํ์์ ๋ชจ๋ ์ ๋ณด ์กฐํ
UsersVO inquiryOfUserById(String id) throws Exception;
//์ ์ ๋ฒํธ๋ก ํ์์ ๋ชจ๋ ์ ๋ณด ์กฐํ
UsersVO inquiryOfUserByUserNo(int userNo) throws Exception;
//ํ๋กํ ์ฌ์ง ์ญ์
void deleteUserImg(int userNo) throws Exception;
//๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ
void modifyPw(UsersVO user) throws Exception;
//ํ์ ํํด
void withdrawal(UsersVO user) throws Exception;
}
์ธํฐํ์ด์ค๋ฅผ ์์ฑํด์ ์ธ์ ํ ํ๋ฆฟ์ ์ฌ์ฉํ์ง ์๊ณ ๋งคํผ ์ ์ฒด๋ฅผ ๊ตฌํ ํด๋์ค๋ก ์ฌ์ฉํ๋๋ก ํ์๋ค.
ํ์ํ ๊ฒ ๊ฐ์ ๊ธฐ๋ฅ๋ค์ ๋ง๋ค๋ฉด์ ์ถ๊ฐํ์๋ค. ํ์๊ฐ์ ๊ณผ ๋ก๊ทธ์ธ ๋ก์ง์ ๊ฐ๋จํ๊ฒ ๋์๋๋ฐ ํ์์ ๋ณด ๋ก์ง์์ ๊ทธ๋๋ง๋ค ํ์ํ ๊ธฐ๋ฅ๋ค์ ์ถ๊ฐํ๋ค๋ณด๋ ์ด์ง ๋ณต์กํด์ง ๊ฒ๊ฐ์ ๋๋. ํ๋กํ ์ฌ์ง ์ฒ๋ฆฌํ๋๊ฒ ์ ์ผ ๊ณจ์น๊ฐ ์ํ ์.
- ํ์๊ฐ์ ๋ก์ง - ํ์๊ฐ์ , ์ด๋ฉ์ผ ์ค๋ณตํ์ธ, ์์ด๋ ์ค๋ณตํ์ธ
- ๋ก๊ทธ์ธ ๋ก์ง - ๋ก๊ทธ์ธ ์๋ํ ํ์์ ์ ๋ณด ์กฐํ
- ํ์์ ๋ณด ๋ก์ง - ํ์์ ๋ณด ์์ , ์ฒจ๋ถํ์ผ db์์ ์กฐํ, ํ๋กํ ์ฌ์ง ๋ฑ๋ก, ์์ด๋๋ก ํ์์ ๋ณด ์กฐํ, ์ ์ ๋ฒํธ๋ก ํ์์ ๋ณด ์กฐํ, ํ๋กํ ์ฌ์ง ์ญ์ , ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ, ํ์ ํํด
Mapper
UsersMapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hastagram.myapp.users.repository.IUsersDAO">
<!-- UserResultMap ์ค์ -->
<resultMap type="com.hastagram.myapp.users.model.UsersVO" id="UsersResultMap">
<!-- primary key๋ idํ๊ทธ -->
<id property="userNo" column="user_no" />
<!-- ๋๋จธ์ง๋ resultํ๊ทธ -->
<result property="email" column="email"/>
<result property="id" column="id"/>
<result property="pw" column="pw"/>
<result property="name" column="name"/>
<result property="intro" column="intro"/>
<result property="phone" column="phone"/>
<result property="regDate" column="regDate"/>
<result property="profileName" column="profile_name" />
<result property="profileSize" column="profile_size" />
<result property="profileContentType" column="profile_content_type" />
<result property="fileData" column="file_data" />
</resultMap>
<resultMap type="com.hastagram.myapp.users.model.UserImgsVO" id="UserImgsResultMap">
<id property="userImgNo" column="user_img_no" />
<result property="userNo" column="user_no" />
<result property="profileName" column="profile_name" />
<result property="profileSize" column="profile_size" />
<result property="profileContentType" column="profile_content_type" />
<result property="profileData" column="profile_data" />
</resultMap>
<!-- ///////////////////// ํ์๊ฐ์
๋ก์ง ///////////////////// -->
<!-- ํ์ ๋ฑ๋ก SQL -->
<insert id="register">
insert into users(email, id, pw, name) values(#{email}, #{id}, #{pw}, #{name})
</insert>
<!-- ์ด๋ฉ์ผ ์ค๋ณตํ์ธ SQL -->
<select id="isDuplicateEmail" resultType="int">
select count(*)
from users
where email=#{email}
</select>
<!-- ์์ด๋ ์ค๋ณตํ์ธ SQL -->
<select id="isDuplicateId" resultType="int">
select count(*)
from users
where id=#{id}
</select>
<!-- ///////////////////// ๋ก๊ทธ์ธ ๋ก์ง ///////////////////// -->
<!-- ํ์์ ๋ณด ์กฐํ ๋์ SQL ์ฒ๋ฆฌ -->
<select id="login" resultMap="UsersResultMap">
select
U.user_no as user_no,
email,
id,
pw,
name,
intro,
phone,
reg_date,
I.user_img_no as user_img_no,
I.profile_name as profile_name,
I.profile_size as porfile_size,
I.profile_content_type as profile_content_type
from users U
left outer join user_imgs I
on U.user_no = I.user_no
where email=#{email}
</select>
<!-- ///////////////////// ํ์ ์ ๋ณด ๋ก์ง ///////////////////// -->
<!-- ํ์ ์ ๋ณด ์์ ๊ธฐ๋ฅ -->
<update id="modifyInfo">
update users set id=#{id}, email=#{email}, name=#{name}, intro=#{intro}, phone=#{phone} where user_no=#{userNo}
</update>
<!-- ํ์ผ ์กฐํ ๊ธฐ๋ฅ -->
<select id="getProfile" resultMap="UserImgsResultMap">
select * from user_imgs where user_no=#{userNo}
</select>
<!-- ํ๋กํ ์ฌ์ง ๋ฑ๋ก ๊ธฐ๋ฅ -->
<insert id="insertUserImg">
insert into user_imgs (user_no, profile_name, profile_size, profile_content_type, profile_data) values (#{userNo}, #{profileName}, #{profileSize}, #{profileContentType}, #{profileData})
</insert>
<!-- ์์ด๋๋ก ํ์ ๋ชจ๋ ์ ๋ณด ์กฐํ ๊ธฐ๋ฅ -->
<select id="inquiryOfUserById" resultMap="UsersResultMap">
select
U.user_no as user_no,
email,
id,
pw,
name,
intro,
phone,
reg_date,
I.user_img_no as user_img_no,
I.profile_name as profile_name,
I.profile_size as porfile_size,
I.profile_content_type as profile_content_type
from users U
left outer join user_imgs I
on U.user_no = I.user_no
where id=#{id};
</select>
<!-- ํ์ ๋ฒํธ๋ก ํ์ ๋ชจ๋ ์ ๋ณด ์กฐํ ๊ธฐ๋ฅ -->
<select id="inquiryOfUserByUserNo" resultMap="UsersResultMap">
select
U.user_no as user_no,
email,
id,
pw,
name,
intro,
phone,
reg_date,
I.user_img_no as user_img_no,
I.profile_name as profile_name,
I.profile_size as porfile_size,
I.profile_content_type as profile_content_type
from users U
left outer join user_imgs I
on U.user_no = I.user_no
where U.user_no=#{userNo};
</select>
<!-- ํ๋กํ ํ์ผ ์ญ์ -->
<delete id="deleteUserImg">
delete from user_imgs where user_no = #{userNo}
</delete>
<!-- ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ๊ธฐ๋ฅ -->
<update id="modifyPw">
update users set pw=#{pw} where user_no=#{userNo}
</update>
<!-- ํ์ ํํด ๊ธฐ๋ฅ -->
<delete id="withdrawal">
delete from users where user_no=#{userNo}
</delete>
</mapper>
๋งคํผ ์์ฑ
๊ตฌํํด๋์ค๋ฅผ ๋ง๋ค์ง ์๊ณ ๋งคํผ.xml ํ์ผ ์์ฒด๋ฅผ ํด๋์ค, ์๋ฐ๊ฐ์ฒด๋ก ์ฌ์ฉ. ๊ทธ๋ฅ ๋๋ฉด ์๊ฐ ๊ตฌํ ํด๋์ค์ธ์ค ๋ชจ๋ฅด๋๊น ์ถ๊ฐ๋ก mvc-config.xml ์์ ์ค์ ์ ํด์ฃผ์ด์ผํ๋ค.
<!-- [Mapper.xml ํ์ผ ๋น๊ฐ์ฒด๋ก ๋ฑ๋ก (=@Repository)] -->
<mybatis-spring:scan base-package="com.hastagram.myapp.users.repository"/>
id์ ๋ฉ์๋ ๋ช ์ ๋์ผํ๊ฒ ์์ฑํ ๊ฒ. ResultMap ๋ง๋ค๊ธฐ. ์๋ฆฌ์์ค ์ฒ๋ฆฌ๋ ์ํด๋๋๋ค.
(๋ค๋ฅธ ๊ฒ์ํ ๋ง๋ค๋๋ ์๋ฆฌ์์ค ์ฒ๋ฆฌ๋ฅผ ํ์๋๋ฐ ์ด๋ฒ์ ์ํด๋๋๋ค. why? type์ ์ ์ฒด ๊ฒฝ๋ก๋ฅผ ์ ์ด๋์๊ธฐ ๋๋ฌธ์ ์๋ฆฌ์์ค ์ค์ ์ ์ํด๋๋๋ค. ์๋ฆฌ์์ค->๊ธธ๊ฒ ์ฐ๊ธฐ ๊ท์ฐฎ์์ ๋ณ์นญ์ ์ง์ ํด์ฃผ๋ ์กด์ฌ)
Test
JUnit Test
package com.hastagram.myapp.userstest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.hastagram.myapp.users.model.LoginVO;
import com.hastagram.myapp.users.model.UsersVO;
import com.hastagram.myapp.users.repository.IUsersDAO;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:/spring/mvc-config.xml"})
public class UsersDAOTest {
@Autowired
private IUsersDAO usersDAO;
//ํ์๊ฐ์
ํ
์คํธ
@Test
public void register() throws Exception {
UsersVO user = new UsersVO();
user.setEmail("qkqh@test.com");
user.setId("qkqh");
user.setPw("123123123!");
usersDAO.register(user);
}
//์ด๋ฉ์ผ ์ค๋ณตํ์ธ ํ
์คํธ
@Test
public void isEmail() throws Exception {
int result = usersDAO.isDuplicateEmail("test@test.com");
if(result == 1) {
System.out.println("์ด๋ฉ์ผ ์ค๋ณต!");
} else {
System.out.println("์ด๋ฉ์ผ ์ฌ์ฉ ๊ฐ๋ฅ!");
}
}
//์์ด๋ ์ค๋ณตํ์ธ ํ
์คํธ
@Test
public void isId() throws Exception {
int result = usersDAO.isDuplicateId("qkqh");
if(result == 1) {
System.out.println("์์ด๋ ์ค๋ณต!");
} else {
System.out.println("์์ด๋ ์ฌ์ฉ ๊ฐ๋ฅ!");
}
}
//๋ก๊ทธ์ธ ํ
์คํธ
@Test
public void login() throws Exception {
//๋ก๊ทธ์ธ vo์์ฑ
LoginVO login = new LoginVO();
login.setEmail("qkqh@test.com");
login.setPw("123123123!");
//๋ก๊ทธ์ธ ์๋ํ ํ์์ ๋ชจ๋ ์ ๋ณด ๊บผ๋ด์ค๊ธฐ
UsersVO user = usersDAO.login(login);
System.out.println("๋ก๊ทธ์ธ ์๋ ํ์ ์ ๋ณด : " + user);
}
//ํ์ ์ ๋ณด ์์
@Test
public void modifyInfo() throws Exception {
UsersVO user = new UsersVO();
user.setUserNo(1);
user.setId("qkRNj");
user.setEmail("gjgjgj@naver.com");
user.setName("๋ฐ๋ณด์จ");
user.setIntro("์๋
ํ์ผ");
user.setPhone("010-333-3333");
usersDAO.modifyInfo(user);
}
//๋น๋ฐ๋ฒํธ ์์
@Test
public void updatePw() throws Exception {
UsersVO user = new UsersVO();
user.setUserNo(2);
user.setPw("gkgkkkggkkgk");
usersDAO.modifyPw(user);
}
//ํ์ ํํด ํ
์คํธ
@Test
public void delelte() throws Exception {
UsersVO user = new UsersVO();
user.setUserNo(2);
usersDAO.withdrawal(user);
}
ํ ์คํธ๋ junit์ผ๋ก ํ์๊ณ user๊ธฐ๋ฅ ๋ชจ๋ ๋ฌธ์ ์์ด ๋์ํ๋ค.
Service
IUsersService
package com.hastagram.myapp.users.service;
import com.hastagram.myapp.users.model.LoginVO;
import com.hastagram.myapp.users.model.UserImgsVO;
import com.hastagram.myapp.users.model.UsersVO;
public interface IUsersService {
/*************** ํ์๊ฐ์
๋ก์ง ***************/
//ํ์ ๊ฐ์
์ฒ๋ฆฌ
void register(UsersVO user) throws Exception;
//์ด๋ฉ์ผ ์ค๋ณตํ์ธ ์ฒ๋ฆฌ
int isDuplicateEmail(String email) throws Exception;
//์์ด๋ ์ค๋ณตํ์ธ ์ฒ๋ฆฌ
int isDuplicateId(String id) throws Exception;
/*************** ๋ก๊ทธ์ธ ๋ก์ง ***************/
//๋ก๊ทธ์ธ ์๋ ํ์์ ๋ณด ์กฐํ ์ฒ๋ฆฌ
UsersVO login(LoginVO login) throws Exception;
/*************** ํ์ ์ ๋ณด ๋ก์ง ***************/
//ํ์ ์ ๋ณด ์์
void modifyInfo(UsersVO user) throws Exception;
//์ฒจ๋ถํ์ผ์ DB์์ ๋ถ๋ฌ์ค๊ธฐ
UserImgsVO getProfile(int userNo) throws Exception;
//ํ๋กํ ์ฌ์ง ๋ฑ๋ก
void insertUserImg(UserImgsVO file) throws Exception;
//์์ด๋๋ก ํ์์ ๋ชจ๋ ์ ๋ณด ์กฐํ
UsersVO inquiryOfUserById(String id) throws Exception;
//์ ์ ๋ฒํธ๋ก ํ์์ ๋ชจ๋ ์ ๋ณด ์กฐํ
UsersVO inquiryOfUserByUserNo(int userNo) throws Exception;
//ํ๋กํ ์ฌ์ง ์ญ์
void deleteUserImg(int userNo) throws Exception;
//๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ
void modifyPw(UsersVO user) throws Exception;
//๋น๋ฐ๋ฒํธ ์ฐพ๊ธฐ
String findPw(LoginVO login) throws Exception;
//ํ์ ํํด
void withdrawal(UsersVO user) throws Exception;
}
์ธํฐํ์ด์ค ์์ฑ ํ ๊ตฌํ ํด๋์ค UserService๋ ์์ฑ
Controller
UsersController
@RestController
@RequestMapping("/user")
public class UsersController {
private static final Logger logger = LoggerFactory.getLogger(UsersController.class);
@Autowired
private IUsersService usersService;
Restfulํ๊ฒ URI๋ฅผ ๊ตฌ์ฑํ๊ฒ ๋ค -> @RestController
๊ณตํต URL @RequestMapping -> /user
'Project > Instagram' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[spring] ํด๋ก ์ฝ๋ฉ06 User - ๋ก๊ทธ์์ (0) | 2020.04.08 |
---|---|
[spring] ํด๋ก ์ฝ๋ฉ05 User - ๋ก๊ทธ์ธ, ์ธ์ (0) | 2020.04.08 |
[spring] ํด๋ก ์ฝ๋ฉ04 User - ์ค๋ณตํ์ธ (0) | 2019.11.30 |
[spring] ํด๋ก ์ฝ๋ฉ03 User - ํ์๊ฐ์ (0) | 2019.11.29 |
[spring] ํด๋ก ์ฝ๋ฉ01 ๊ณํ, ์ด๊ธฐ์ค์ , Git (0) | 2019.11.28 |
- Total
- Today
- Yesterday
- ์ ์ฒด๊ฒ์๋ฌผ ์กฐํ
- tomcat์ค์น
- ๊ฒ์๋ฌผ์กฐํ
- ๋ถํธ ์๋์์ฑ
- typeAliases
- ์จ๋ฆฌ์์ค
- ๋ณ๋ช ์ฒ๋ฆฌ
- Java
- ๊ฒ์ํ ์กฐํ
- ์คํ๋ง๋ถํธ ์๋์์ฑ
- ์๋ฐ
- ์ดํด๋ฆฝ์ค ์ค์น
- ์๋ฃ๊ตฌ์กฐ
- ๊ฐ๋ฐ
- Algorithm
- ๊ฒ์ํ ์ญ์
- mysql์ค์น
- ์ดํด๋ฆฝ์ค ํ๊ธ ์ธ์ฝ๋ฉ
- ์๊ณ ๋ฆฌ์ฆ
- java jdk ์ค์น
- ๊ฐ๋ฐํ๊ฒฝ๊ตฌ์ถ
- java ํ๊ฒฝ๋ณ์
- ๊ฒ์๋ฌผ ์ญ์
- ๊ฒ์ํ๋ง๋ค๊ธฐ
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |