0. 방명록 만들기 실습
- Spring JDBC를 이용한 DAO 작성
- Controller + Service + DAO
- 트랜잭션 처리
- Spring MVC에서 form 값 입력받기
- Spring MVC에서 redirect하기
- Controller에서 jsp에게 전달한 값을 JSTL과 EL을 이용해 출력하기
요구사항
요구사항 1
- 방명록 정보는 guestbook 테이블에 저장됨
- id는 자동으로 입력됨
- id, 이름, 내용, 등록일을 저장함
요구사항 2
- http://localhost:8080/guestbook 을 요청하면 자동으로 /guestbook/list로 리다이렉트 함
- 방명록이 없으면 건수는 0이 나오고, 아래에 방명록을 입력하는 form이 보여짐
요구사항 3
- 이름과 내용을 입력하고, 등록 버튼을 누르면 /guestbook/write URL로 입력한 값을 전달하여 저장함
- 값이 저장된 이후에는 /guestbook/list로 리다이렉트 됨
요구사항 4
- 입력한 한 건의 정보가 보여짐
- 방명록 내용과 폼 사이의 숫자는 방명록 페이지 링크. 방명록 5건당 1페이지로 설정함
요구사항 5
- 방명록이 6건 입력되면, 아래 페이지 수가 2건 보여짐
- 1페이지를 누르면 /guestbook/list?start=0 을 요청
- 2페이지를 누르면 /guestbook/list?start=5 을 요청
- /guestbook/list 는 /guestbook/list?start=0 와 결과가 같음
요구사항 6
- 방명록에 글을 쓰거나, 방명록의 글을 삭제할 때는 Log 테이블에 클라이언트의 id 주소, 등록/삭제 시간, 등록/삭제 정보를 DB에 저장함
- 사용하는 테이블은 Log
- id는 자동으로 입력되도록 함
테이블 및 다이어그램
1. 프로젝트 생성 및 설정 파일 생성
# pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>guestbook</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>guestbook</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jsp-api</artifactId>
<version>9.0.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
# WebMvcContextConfiguration.java
package com.example.guestbook.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.example.guestbook.controller"})
public class WebMvcContextConfiguration implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(31556926);
registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
}
@Override
public void addViewControllers(final ViewControllerRegistry registry) {
System.out.println("addViewControllers 호출됨");
registry.addViewController("/").setViewName("index");
}
@Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
# DBConfig.java
package com.example.guestbook.config;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
public class DBConfig implements TransactionManagementConfigurer {
private String driverClassName = "com.mysql.cj.jdbc.Driver";
private String url = "jdbc:mysql://localhost:3306/connectdb?useUnicode=true&characterEncoding=utf8";
private String username = "connectuser";
private String password = "connectuser";
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return transactionManager();
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
# ApplicationConfig.java
package com.example.guestbook.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@ComponentScan(basePackages = {"com.example.guestbook.dao", "com.example.guestbook.service"})
@Import({DBConfig.class})
public class ApplicationConfig {
}
# web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>Spring JavaConfig Sample</display-name>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.example.guestbook.config.ApplicationConfig</param-value>
</context-param>
<listner> <!-- ApplicationConfig를 읽어들이기 위해. 특정한 이벤트가 일어났을 때 동작. Context가 로딩될 때 해당 클래스를 실행해줘 -->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listner>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.example.guestbook.config.WebMvcContextConfiguration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- Layered Architecture 특징 상, 설정 파일을 분리함
- ApplicationConfig 를 읽어들이기 위해 ContextLoaderListener 사용
- run on Server, 서버가 올라가면, Context 가 로딩되면, Listener인 ContextLoaderListener를 실행해줘
- 이때 <context-param>에 등록된 정보를 참고함 -> ApplicationConfig 지정해둠
- <filter> : 요청이 수행되기 전, 응답이 나가기 전에 실행. 한글 인코딩 처리
# index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
response.sendRedirect("guestbook/list");
%>
- "/" 접속 시 "/guestbook/list" 로 리다이렉트
2. DB에 테이블 생성
3. DTO 및 DAO 생성
3.1. DTO
# Guestbook.java
package com.example.guestbook.dto;
import java.util.Date;
public class Guestbook {
private Long id;
private String name;
private String content;
private Date regdate;
public Guestbook(Long id, String name, String content, Date regdate) {
this.id = id;
this.name = name;
this.content = content;
this.regdate = regdate;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getRegdate() {
return regdate;
}
public void setRegdate(Date regdate) {
this.regdate = regdate;
}
@Override
public String toString() {
return "Guestbook{" +
"id=" + id +
", name='" + name + '\'' +
", content='" + content + '\'' +
", regdate=" + regdate +
'}';
}
}
# Log.java
package com.example.guestbook.dto;
import java.util.Date;
public class Log {
private Long id;
private String ip;
private String method;
private Date regdate;
public Log() {}
public Log(Long id, String ip, String method, Date regdate) {
this.id = id;
this.ip = ip;
this.method = method;
this.regdate = regdate;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Date getRegdate() {
return regdate;
}
public void setRegdate(Date regdate) {
this.regdate = regdate;
}
@Override
public String toString() {
return "Log{" +
"id=" + id +
", ip='" + ip + '\'' +
", method='" + method + '\'' +
", regdate=" + regdate +
'}';
}
}
3.2. DAO
# LogDao.java
package com.example.guestbook.dao;
import com.example.guestbook.dto.Log;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.util.List;
@Repository
public class LogDao {
private NamedParameterJdbcTemplate jdbc;
private SimpleJdbcInsert insertAction;
private RowMapper<Log> rowMapper = BeanPropertyRowMapper.newInstance(Log.class);
public LogDao(DataSource dataSource) {
this.jdbc = new NamedParameterJdbcTemplate(dataSource);
this.insertAction = new SimpleJdbcInsert(dataSource)
.withTableName("log")
.usingGeneratedKeyColumns("id"); // id가 자동으로 입력되도록
}
public Long insert(Log log) {
SqlParameterSource params = new BeanPropertySqlParameterSource(log);
return insertAction.executeAndReturnKey(params).longValue(); // 자동으로 생성된 id 값을 리턴하도록
}
}
# GuestBoojDaoSqls.java
package com.example.guestbook.dao;
public class GuestbookDaoSqls {
public static final String SELECT_PARCING = "SELECT id, name, content, regdate FROM guestbook ORDER BY id DESC limit :start, :limit";
public static final String DELETE_BY_ID = "DELETE FROM guestbook WHERE id = :id";
public static final String SELECT_COUNT = "SELECT count(*) FROM guestbook";
}
# GuestbookDao.java
package com.example.guestbook.dao;
import com.example.guestbook.dto.Guestbook;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.example.guestbook.dao.GuestbookDaoSqls.*;
@Repository
public class GuestbookDao {
private NamedParameterJdbcTemplate jdbc;
private SimpleJdbcInsert insertAction;
private RowMapper<Guestbook> rowMapper = BeanPropertyRowMapper.newInstance(Guestbook.class);
public GuestbookDao(DataSource dataSource) {
this.jdbc = new NamedParameterJdbcTemplate(dataSource);
this.insertAction = new SimpleJdbcInsert(dataSource).withTableName("guestbook").usingGeneratedKeyColumns("id");
}
public List<Guestbook> selectAll(Integer start, Integer limit) {
Map<String, Integer> params = new HashMap<>();
params.put("start", start);
params.put("limit", limit);
return jdbc.query(SELECT_PARCING, params, rowMapper);
}
public Long insert(Guestbook guestbook) {
SqlParameterSource params = new BeanPropertySqlParameterSource(guestbook);
return insertAction.executeAndReturnKey(params).longValue();
}
public int deleteById(Long id) {
Map<String, ?> params = Collections.singletonMap("id", id);
return jdbc.update(DELETE_BY_ID, params);
}
public int selectCount() {
return jdbc.queryForObject(SELECT_COUNT, Collections.emptyMap(), Integer.class);
}
}
3.3. 테스트
# GuestbookDaoTest.java
package com.example.guestbook.dao;
import com.example.guestbook.config.ApplicationConfig;
import com.example.guestbook.dto.Guestbook;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Date;
public class GuestbookDaoTest {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
GuestbookDao guestbookDao = ac.getBean(GuestbookDao.class);
Guestbook guestbook = new Guestbook();
guestbook.setName("Jeon");
guestbook.setContent("스프링 아자자");
guestbook.setRegdate(new Date());
Long id = guestbookDao.insert(guestbook);
System.out.println("id: " + id);
}
}
# LogDaoTest.java
package com.example.guestbook.dao;
import com.example.guestbook.config.ApplicationConfig;
import com.example.guestbook.dto.Log;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Date;
public class LogDaoTest {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
LogDao logDao = ac.getBean(LogDao.class);
Log log = new Log();
log.setIp("127.0.0.1");
log.setMethod("insert");
log.setRegdate(new Date());
Long id = logDao.insert(log);
System.out.println("id: " + id);
}
}
4. Service 생성
# GuestbookService.java
package com.example.guestbook.service;
import com.example.guestbook.dto.Guestbook;
import java.util.List;
public interface GuestbookService {
public static final Integer LIMIT = 5;
public List<Guestbook> getGuestbooks(Integer start);
public int deleteGuestbook(Long id, String ip);
public Guestbook addGuestbook(Guestbook guestbook, String ip);
public int getCount();
}
# GuestbookServiceImpl.java
package com.example.guestbook.service.impl;
import com.example.guestbook.dao.GuestbookDao;
import com.example.guestbook.dao.LogDao;
import com.example.guestbook.dto.Guestbook;
import com.example.guestbook.dto.Log;
import com.example.guestbook.service.GuestbookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@Service
public class GuestbookServiceImpl implements GuestbookService {
@Autowired // 알아서 GuestbookDao를 생성해서 주입해줌
GuestbookDao guestbookDao;
@Autowired
LogDao logDao;
@Override
@Transactional // 읽기만 하는 메소드인 경우 트랜잭션을 위해 사용 readOnly == true
public List<Guestbook> getGuestbooks(Integer start) {
List<Guestbook> list = guestbookDao.selectAll(start, GuestbookService.LIMIT);
return list;
}
@Override
@Transactional(readOnly = false)
public int deleteGuestbook(Long id, String ip) {
int deletedCount = guestbookDao.deleteById(id);
Log log = new Log();
log.setIp(ip);
log.setMethod("delete");
log.setRegdate(new Date());
logDao.insert(log);
return deletedCount;
}
@Override
@Transactional(readOnly = false)
public Guestbook addGuestbook(Guestbook guestbook, String ip) {
guestbook.setRegdate(new Date());
Long insertedId = guestbookDao.insert(guestbook); // insert해서 자동으로 만들어진 id 값을 얻어옴
guestbook.setId(insertedId);
Log log = new Log();
log.setIp(ip);
log.setMethod("insert");
log.setRegdate(new Date());
logDao.insert(log);
return guestbook;
}
@Override
public int getCount() {
return guestbookDao.selectCount();
}
}
테스트
# GuestbookServiceTest.java
package com.example.guestbook.service.impl;
import com.example.guestbook.config.ApplicationConfig;
import com.example.guestbook.dto.Guestbook;
import com.example.guestbook.service.GuestbookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class GuestbookServiceTest {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
GuestbookService guestbookService = ac.getBean(GuestbookService.class);
Guestbook guestbook = new Guestbook();
guestbook.setName("soyeong");
guestbook.setContent("안녕하세용");
Guestbook result = guestbookService.addGuestbook(guestbook, "127.0.0.1");
System.out.println(result);
}
}
5. Controller 생성
# GuestbookController.java
package com.example.guestbook.controller;
import com.example.guestbook.dto.Guestbook;
import com.example.guestbook.service.GuestbookService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.ArrayList;
import java.util.List;
@Controller
public class GuestbookController {
@Autowired // Service를 사용하기 위해 주입
GuestbookService guestbookService;
@GetMapping("/list")
public String list(@RequestParam(name = "start", required = false, defaultValue = "0") int start,
ModelMap model) {
// start로 시작하는 방명록 목록 구하기
List<Guestbook> list = guestbookService.getGuestbooks(start);
// 전체 페이지 수 구하기
int count = guestbookService.getCount();
int pageCount = count / GuestbookService.LIMIT;
if(count % GuestbookService.LIMIT > 0) pageCount++;
// 페이지 수만큼 start의 값을 리스트로 저장
// 페이지 수가 3이라면, 0, 5, 10 저장
List<Integer> pageStartList = new ArrayList<>();
for(int i = 0; i < pageCount; i++) {
pageStartList.add(i * GuestbookService.LIMIT);
}
model.addAttribute("list", list);
model.addAttribute("count", count);
model.addAttribute("pageStartList", pageStartList);
return "list"; // list.jsp로 넘겨줌
}
@PostMapping("/write")
public String write(@ModelAttribute Guestbook guestbook, HttpServletRequest request) {
String clientIp = request.getRemoteAddr();
// System.out.println("clientIp: " + clientIp);
guestbookService.addGuestbook(guestbook, clientIp);
return "redirect:list";
}
}
6. View 생성
# list.jsp
<%--
Created by IntelliJ IDEA.
User: jeonsoyeong
Date: 2023/06/27
Time: 6:47 PM
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>방명록 목록</title>
</head>
<body>
<h1>방명록</h1>
<br> 방명록 전체 수 : ${count }
<br>
<br>
<c:forEach items="${list}" var="guestbook">
${guestbook.id} ${status.index}<br>
${guestbook.name} ${status.index}<br>
${guestbook.content} ${status.index}<br>
${guestbook.regdate} ${status.index}<br>
</c:forEach>
<br>
<c:forEach items="${pageStartList}" var="pageIndex" varStatus="status">
<a href="list?start=${pageIndex}">${status.index +1 }</a>
</c:forEach>
<br>
<br>
<form method="post" action="write">
name : <input type="text" name="name"><br>
<textarea name="content" cols="60" rows="6"></textarea>
<br> <input type="submit" value="등록">
</form>
</body>
</html>
'강의 노트 > 웹 프로그래밍(풀스택)' 카테고리의 다른 글
[boostcourse] 5.4. Cookie & Session - BE (0) | 2023.07.10 |
---|---|
[boostcourse] 3.11. Controller - BE (0) | 2023.07.09 |
[boostcourse] 3.10. Layered Architecture - BE (1) (0) | 2023.06.27 |
[boostcourse] 3.9. Spring MVC - BE (2) (0) | 2023.06.26 |
[boostcourse] 3.9. Spring MVC - BE (1) (0) | 2023.06.26 |