Spring 02

JSPとSpring Boot

JSP maven
<!-- spring boot tomcat jsp-->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
</dependency>

Servlet maven

<!--servlet-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
</dependency>

JSTL maven
<!-- jstl-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>


JSPを利用するために、JSPのフォルダーを指定します。
application.properties
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

下記のは、もし/indexへ遷移したら、springmvcがJSPのフォルダーのindex.jspを探します。

@Controller
public class IndexController {
    @RequestMapping(value = "/index",method = RequestMethod.GET)
    public String index(){
        return "index";
    }
}

@Controller
使用者からもらったURLを対応のサービスに渡します。よくRequestMappingと一緒に使われています。

@RequestMapping
ルーティング情報を提供します。


・SpringBootがSpringDataJPAでCRUDを作ります。
<!--mysql-connector-java-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- spring data jpa -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!--tomcat-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <!--<scope>provided</scope>-->
</dependency>

内部のtomcatで実行する場合は、scopeを削除します。

@ResponseBody
戻り値をHTTP response bodyに書き込みます。

@RestController
JsonXML等を返すWebAPI用のコントローラで使用します。


・DataBaseの接続とJPA(Java Persistence API )
下記の二つは同じ機能ですが、一つのコードは長いです。もう一つは短くて、理解やすいです。しかし、yaml形式の定義ファイルはpropertiesのルールより厳しいです。一つスペースも影響されています。

(application.properties)
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=matt
spring.datasource.password=12345
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

(application.yml)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: matt
    password: 12345
    driver-class-name: com.mysql.cj.jdbc.Driver

Hibernate
Java のためのORM(Object-Relational Mapping) ライブラリであり、オブジェクト指向ドメインモデルを関係データベースにマッピングするためのフレームワークを提供します。

@Entity
テーブルを指定します。

@Table
よく@Entityと一緒に使われています。

@id
一つテーブルは一つprimary keyしかありません。

@GeneratedValue
primary key生成方法です。AUTO、INDENTITY、SEQUENCEとTABLE 四つ方法があります。既定値はAUTOです。

@Column
特定のデータを指定します。特定の属性を指定することができます。今回は使用しません。

@Autowired
Beanから自動的に導入します。

JpaRepository
SpringDataJPAが提供した簡単なデータ操作インターフェースです

JpaSpecificationExecutor
SpringDataJPAが提供した複雑な検査インターフェースです。

Serializable
直列化インターフェースです。

・DataBaseの接続問題
原因:mysql-connector-java の5.1.33 ~ 37 のバグでした。
詳しいページ:https://www.nakamuri.info/mw/index.php/Mysql-connector-java_%E3%81%AE%E3%83%90%E3%82%B0%E3%81%A7_Java%E3%81%8B%E3%82%89MySQL%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84
以前
url: jdbc:mysql://localhost:3306/test_01?characterEncoding=utf8
現在
url: jdbc:mysql://localhost:3306/test_01?characterEncoding=UTF-8&serverTimezone=JST


CRUDを作成しました。
バグ:Create機能は実行できません。
原因:sequenceでprimary keyを生成するのは、MySQLに対してサポートしません。MySQLはidentityを使っています。
解決方法:@GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY)

Spring 01

Springのホームページ

https://spring.io/

 

pom.xml (Project Object Model)

https://mvnrepository.com/ 


Modelがこのページにもらえます。もらったら、pom.xmlに貼り付けます。

 

web.xml
どちらのcontrollerで実行するのは、web.xmlで決めます。

 

src/main/java
プロジェクトのビジネス ロジック プログラムなどの一般的なコードを配置するために使用される所です。

 

src/main/resources
property、xml、profileなどのstatic resourceを配置するために使用される所です。

 

src/test/java
単体test codeなどのtest codeを配置するために使用される所です。

 

・Spring MVC

(1)DispatcherServlet

フロントコントローラーです。全てのリクエストはDispatcherServletを通して配信され、対応するhandlerに配信されます。

 

(2)HandlerMapping

要求リンクを解析して、要求リンクに基づいて要求を実行したクラス(HandlerMappingというハンドラー)を見つけます。

 

(3)HandlerAdapter

使用者からのリクエストによってメソッドを呼んで、処理します。

 

(4)Controller

Controllerは使用者のリクエストを処理して、Controllerが終わったら、DispatcherServletにModelとViewのオブジェクトを渡します。

 

他の角度で見たら、DispatcherServletはWebアプリケーション全体のコントローラーです。Controllerは単一のHttp要求処理におけるコントローラーです。

 

(5)ViewResolver
Viewを解析し、View内の論理名を実際のViewオブジェクトに変更します。

 

(6)Model
アプリケーションデータ、ビジネスルール、ロジック、関数などです。

 

(7)Service
ビジネスロジックの処理、処理された結果のControllerへの返却、またはDAOの呼び出しによるデータベースへの格納を担当します。

 

ログイン画面(DataBaseなし)


(pom.xml
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>

 

(web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value> <!-- Spring Security's setting file is change to classpath(applicationContxt.xml) -->
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

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

<security:http auto-config='true'>
<security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
</security:http>

<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="matt" password="matt" authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>

</beans:beans>

プログラミング中、あった問題 14

JSPがクラスから直接にメソッドを呼びます。
クラス名.メソッド名();


・メソッドを呼ぶ時、値をもらいます。
value=クラス名.メソッド名();


・メソッドを呼ぶ時、staticで定義します。
public static データ型 メソッド名


・メソッドがstaticで定義したら、エラーになります。
原因は同じクラスの変数を使っています。

 

結論:JSPがクラスからメソッドを呼べません。

 

 

・新しいメソッドを作ります。
public static データ型 メソッド名


・新しいメソッドが既存の値をもらう方法

(既存の値はDataBaseからもらった値です。)


メソッドを呼ぶ時、値を入れます。
クラス名.メソッド名(値);


・どこから入れる値をもらいます。


JSP
String 変数名 = (String) request.getAttribute("変数名");
クラス名.メソッド名(値);


Beans
クラス名.メソッド名(値);

 

結論:JSPで値を渡すなら、一度Beansから値をもらうことが必要です。

Beansで渡すなら、新しいメソッドは何を処理したほうがいいですか?

そして、JSPは同じBeansから値をもらいます。

新しいメソッドを作ることが必要ないと思います。

 

 

・値をもらう方法
String 変数名 = (String) request.getAttribute("変数名");


・上記の方法でメソッドをもらいます。
できないと思います。

 

・複数メソッドを作ります。
コードが長くなって、値も一つ一つもらいます。

 

結論:明確に特定の値を処理するのはいいですが、似ているメソッドが存在するのは必要ないと思います。

 

 

配列の配列
複数の配列をまとめることができます。

しかし、デバッグで検査する時、配列は長くなります。


この問題について、新しい変数を作って、

何番目の配列を指定するなら、検査することが簡単になります。

 

ArrayList<ArrayList<String>> 配列名 = new ArrayList<>();
配列名.add(配列1);
配列名.add(配列2);
配列名.add(配列3);
配列名.get(0);

 

結論:JSPで新しい変数を定義することが必要ないです。

以前はBeansとJSPが新しい変数を追加しなければなりません。

今はBeansで新しい変数を作って、JSPでその配列を指定すると、結果を出ます。

 


Spring Frameworkとは
フレームワークは自身で実行することができません。開発者のコードと一緒にのは完全なアプリケーションです。フレームワークは共通のプログラムをまとめので、再利用するのは可能です。フレームとは枠です。開発者たちがこの枠の下にプログラミングします。枠に開発のスビートが早くて、開発者のコードも一致性が高いです。将来に修正することが簡単になります。しかし、フレームワークの仕様要件を超えるなら(拡充機能がない場合)、修正することが難しくなります。本来、フレームワークの自体が制限であることです。


・Frameworkの利点
変更に強い
テストが簡単
拡張性が高い
保守性が高い
再利用性が高い

プログラミング中、あった問題 13

JSPArraylistをもらう方法
ArrayList<String> todo_text1 = (ArrayList<String>)request.getAttribute("todo_text1");

警告があるですが、使えます。
警告:unchecked cast from object to Arraylist<String>

・ループ
問題:複数のArraylistが一つループにプリントしたい場合は、どちら方法は一番いいです?
1.愚直な方法(For)
for(int i = 0; i < list.size(); ++i){
    String s = list.get(i);
    System.out.println(s);
}

2.Iteratorイテレータ)(For)
for(Iterator<String>itr = list.iterator(); itr.hasNext();){
    String s = itr.next();
    System.out.println(s);
}

3.拡張for文
for(String s : list){
    System.out.println(s);
}

4.ラムダ
list.forEach(s -> {
    System.out.println(s);
});

5. ラムダだが、メソッド参照
list.forEach(System.out::println);

6.愚直な方法(while)
int j = 0;
while (list.size() > j) {
    System.out.println(list.get(j));
    j++;
}
7.Iteratorイテレータ)(while)
Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
}


自分の結論:3番の方法を使うなら、一つArraylistしか使えません。イテレータなら、同じ問題だと思います。1番と6番なら、簡単ですが、ループの中にコードがわかりやすいと思います。
(3番)
int i = 0;
for(String result : list01){
    System.out.println(result);            <-list02と使い方は違います。。
    System.out.println(list02.get(i));
    i++;
}
(6番)
int i = 0;
while(list01.size() > i){
    System.out.println(list01.get(i));    <-list02と使い方は同じです。
    System.out.println(list02.get(i));
    i++;
}

プログラミング中、あった問題 12

 

・print_todo機能をまとめました。
実行方法:encodeの部分がSQLの部分に遷移しました。

・edit_todo.jspにもらった値をを二回でエンコードしました。
UserBeansから戻る値の部分を修正しました。

    public String getId_edit() {
        return id;
    }

    public void setId_edit(String id) {
        this.id = id;
    }

    public String getPassword_edit() {
        return password;
    }

    public void setPassword_edit(String password) {
        this.password = password;
    }


・Encode機能を共通関数にします。
package user_todo;

public class CommonBeans {

        public static String EscapeHTMLCharacter(String original) {
        String newString = original;
        newString = newString.replaceAll("(?i)(&)", "&amp;");
        newString = newString.replaceAll("(?i)(')", "&#039;");
        newString = newString.replaceAll("(?i)(\")", "&quot;");
        newString = newString.replaceAll("(?i)(<)", "&lt;");
        newString = newString.replaceAll("(?i)(>)", "&gt;");   
        return newString;
    }
        public static String EscapeSQLCharacter(String original) {
        String newString = original;
        newString = newString.replaceAll("(?i)(')", "''");   
        return newString;
    }
}

使い方:CommonBeans.EscapeHTMLCharacter(userid);   


   
MVC
モデル(Model):データを保存する場所です。
ビュー(View):結果が表示されます。
コントローラ(Controller):データを処理する場所です。


・UserServletsとTodoServletを作成しました。
BeansのSQL指令をServletに遷移しました。

UserServlet
public class UserServlet {
    Timestamp timestamp = new Timestamp(System.currentTimeMillis());
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String time = sdf.format(timestamp);

    // Add New Account
    public static String add_user(String id, String password) {
        id = EscapeCharacter.EscapeSQLCharacter(id);
        password = EscapeCharacter.EscapeSQLCharacter(password);
        String sql = "insert into user(user_id, password) values ('" + id + "','" + password + "')";

        return sql;
    }

    // Delete Account
    public static String delete_user(String id) {
        id = EscapeCharacter.EscapeSQLCharacter(id);
        String sql = "delete from user where user_id=('" + id + "')";
        return sql;
    }

    // Delete user todo
    public static String delete_user_todo(String id) {
        id = EscapeCharacter.EscapeSQLCharacter(id);
        String sql = "delete from todo where user_id=('" + id + "')";
        return sql;
    }

    // Change Password
    public static String change_password(String id, String password) {
        id = EscapeCharacter.EscapeSQLCharacter(id);
        password = EscapeCharacter.EscapeSQLCharacter(password);
        String sql = "UPDATE user SET password ='" + password + "' WHERE user_id = '" + id + "'";
        return sql;
    }
   
    // Select user
    public static StringBuffer select_user(String id,String password) {
        id = EscapeCharacter.EscapeSQLCharacter(id);
        password = EscapeCharacter.EscapeSQLCharacter(password);
        StringBuffer sql = new StringBuffer();
        sql.append("select * from user where user_id = '" + id + "' and password = '" + password + "'");
        return sql;
    }

    // Account Login Verification
    public static StringBuffer verification_user(String id) {
        StringBuffer sql = new StringBuffer();
        sql.append("SELECT `todo_id`,`todo_text`,`finished`,`upload_date` FROM `todo` WHERE user_id = '" + id + "'");
        return sql;
    }

    // Select user_todo
    public static StringBuffer select_todo(String id) {
        StringBuffer sql = new StringBuffer();
        id = EscapeCharacter.EscapeSQLCharacter(id);
        sql.append("SELECT `todo_id`,`todo_text`,`finished`,`upload_date` FROM `todo` WHERE user_id = '" + id + "'");
        return sql;
    }

    // Date_type_convert
    public static String date_convert(String upload_date) {
        upload_date = upload_date.replaceFirst("(?i)(-)", "年");
        upload_date = upload_date.replaceFirst("(?i)(-)", "月");
        upload_date = upload_date.replaceFirst("(?i)( )", "日");
        upload_date = upload_date.substring(0, 16);

        int YEAR = Integer.parseInt(upload_date.substring(0, 4));
        int MONTH = Integer.parseInt(upload_date.substring(5, 7));
        int DATE = Integer.parseInt(upload_date.substring(8, 10));
        MONTH = MONTH - 1;
        DATE = DATE - 1;

        String week = new String[7];
        week[0] = "日";
        week[1] = "月";
        week[2] = "火";
        week[3] = "水";
        week[4] = "木";
        week[5] = "金";
        week[6] = "土";

        Calendar YEAR_MONTH_DATE = Calendar.getInstance();
        YEAR_MONTH_DATE.set(Calendar.YEAR, YEAR);
        YEAR_MONTH_DATE.set(Calendar.MONTH, MONTH);
        YEAR_MONTH_DATE.set(Calendar.DAY_OF_MONTH, DATE);
        int DAY_OF_WEEK = YEAR_MONTH_DATE.get(Calendar.DAY_OF_WEEK);

        upload_date = upload_date.substring(5, 11) + "(" + week[DAY_OF_WEEK] + ")" + upload_date.substring(11, 16);

        return upload_date;
    }
   
TodoServlet
public class TodoServlet {

    Timestamp timestamp = new Timestamp(System.currentTimeMillis());
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String time = sdf.format(timestamp);

    // Add Todo
    public static String add_todo(String id, String data, String time) {
        id = EscapeCharacter.EscapeSQLCharacter(id);
        data = EscapeCharacter.EscapeSQLCharacter(data);
        String sql = "INSERT INTO `company_db`.`todo` (`user_id`, `todo_text`, `finished`, `created_date`, `upload_date`) VALUES ('"
                + id + "', '" + data + "', '0', '" + time + "', '" + time + "')";

        return sql;
    }

    // Delete Todo
    public static String delete_todo(String todo_array) {
        String todo_str = EscapeCharacter.EscapeSQLCharacter(todo_array);
        String sql = "DELETE FROM `company_db`.`todo` WHERE  `todo_id`='" + todo_str + "'";

        return sql;
    }

    // UPDATE Todo
    public static String edit_todo(String todoid, String data, String time) {
        todoid = EscapeCharacter.EscapeSQLCharacter(todoid);
        data = EscapeCharacter.EscapeSQLCharacter(data);
        String sql = "UPDATE `todo` SET `todo_text` ='" + data + "',`upload_date` ='" + time + "' WHERE `todo_id` = '"
                + todoid + "'";
        return sql;

    }

    // Select user_todo
    public static StringBuffer select_todo(String id) {
        StringBuffer sql = new StringBuffer();
        id = EscapeCharacter.EscapeSQLCharacter(id);
        sql.append("SELECT `todo_id`,`todo_text`,`finished`,`upload_date` FROM `todo` WHERE user_id = '" + id + "'");
        return sql;
    }

    // Date_type_convert
    public static String date_convert(String upload_date) {
        upload_date = upload_date.replaceFirst("(?i)(-)", "年");
        upload_date = upload_date.replaceFirst("(?i)(-)", "月");
        upload_date = upload_date.replaceFirst("(?i)( )", "日");
        upload_date = upload_date.substring(0, 16);

        int YEAR = Integer.parseInt(upload_date.substring(0, 4));
        int MONTH = Integer.parseInt(upload_date.substring(5, 7));
        int DATE = Integer.parseInt(upload_date.substring(8, 10));
        MONTH = MONTH - 1;
        DATE = DATE - 1;

        String
week = new String[7];
        week[0] = "日";
        week[1] = "月";
        week[2] = "火";
        week[3] = "水";
        week[4] = "木";
        week[5] = "金";
        week[6] = "土";

        Calendar YEAR_MONTH_DATE = Calendar.getInstance();
        YEAR_MONTH_DATE.set(Calendar.YEAR, YEAR);
        YEAR_MONTH_DATE.set(Calendar.MONTH, MONTH);
        YEAR_MONTH_DATE.set(Calendar.DAY_OF_MONTH, DATE);
        int DAY_OF_WEEK = YEAR_MONTH_DATE.get(Calendar.DAY_OF_WEEK);

        upload_date = upload_date.substring(5, 11) + "(" + week[DAY_OF_WEEK] + ")" + upload_date.substring(11, 16);

        return upload_date;
    }

プログラミング中、あった問題 11

・変数名error_statusがerror_message01に変更しました。
以前
String error_status = (String) request.getAttribute("error_status");
String error_message = (String) request.getAttribute("error_message");

現在
String error_message01 = (String) request.getAttribute("error_message01");
String error_message02 = (String) request.getAttribute("error_message02");


・バグ:記号アカウントのTodo一覧画面のディスプレイ機能は失効しました。
問題点:値を渡す方法は問題があります。
推測原因:Encodeの機能は不完全です。
原因:SQLの値が変わりました。。
解決方法:不要なコードを削除しました。
id = id.replaceAll("(?i)(')", "''");

・バグ:編集機能と削除機能が失効しまいました。
問題点:Encodeは不完全です。
解決方法:デバッグで一つ一つを修正しました。
悪い点:コードは読みづらいです。

以前のEncodeメソッドを削除しました
public Boolean Encode(){
    id = id.replaceAll("(?i)(&)", "&amp;");
    id = id.replaceAll("(?i)(')", "&#039;");
    id = id.replaceAll("(?i)(\")", "&quot;");
    id = id.replaceAll("(?i)(<)", "&lt;");
    id = id.replaceAll("(?i)(>)", "&gt;");
    password = password.replaceAll("(?i)(&)", "&amp;");
    password = password.replaceAll("(?i)(')", "&#039;");
    password = password.replaceAll("(?i)(\")", "&quot;");
    password = password.replaceAll("(?i)(<)", "&lt;");
    password = password.replaceAll("(?i)(>)", "&gt;");
    return true;
}


ModeServletにModeによって指定のメソッドを実行します。
if (result == true && mode.equals("user_verification")
        ||result == true && mode.equals("add_Todo_database")
                ||result == true && mode.equals("delete_Todo_database")){
    userid = userid.replaceAll("(?i)(&)", "&amp;");
    userid = userid.replaceAll("(?i)(')", "&#039;");
    userid = userid.replaceAll("(?i)(\")", "&quot;");
    userid = userid.replaceAll("(?i)(<)", "&lt;");
    userid = userid.replaceAll("(?i)(>)", "&gt;");
    userpassword = userpassword.replaceAll("(?i)(&)", "&amp;");
    userpassword = userpassword.replaceAll("(?i)(')", "&#039;");
    userpassword = userpassword.replaceAll("(?i)(\")", "&quot;");
    userpassword = userpassword.replaceAll("(?i)(<)", "&lt;");
    userpassword = userpassword.replaceAll("(?i)(>)", "&gt;");

    if(mode.equals("user_verification")) {
        request.setAttribute("id", userid);
        request.setAttribute("password", userpassword);
        user.print_todo(request, response);
    }

    if(mode.equals("add_Todo_database")) {
        request.setAttribute("id", userid);
        request.setAttribute("password", userpassword);
        todo.print_todo(request, response);
    }

    if(mode.equals("delete_Todo_database")) {
        request.setAttribute("id", userid);
        request.setAttribute("password", userpassword);
        todo.todo_delete_back(request, response);
    }
}
else if(result == true && mode.equals("edit_Todo_database")){
    request.setAttribute("id", userid);
    request.setAttribute("password", userpassword);
    todo.todo_edit_back(request, response);
}

・バグに対応して、コードを修正しました。
public Boolean print_todo(HttpServletRequest request, HttpServletResponse response) {
        try {
            ResultSet rset = null;
            conn = ds.getConnection();

            StringBuffer sql = new StringBuffer();

            //赤いところは各機能のバグによって修正した部分です。

            id = id.replaceAll("(?i)(&amp;)", "&");
            id = id.replaceAll("(?i)(&#039;)", "'");
            id = id.replaceAll("(?i)(&quot;)", "\"");
            id = id.replaceAll("(?i)(&lt;)", "<");
            id = id.replaceAll("(?i)(&gt;)", ">");
            password = password.replaceAll("(?i)(&amp;)", "&");
            password = password.replaceAll("(?i)(&#039;)", "'");
            password = password.replaceAll("(?i)(&quot;)", "\"");
            password = password.replaceAll("(?i)(&lt;)", "<");
            password = password.replaceAll("(?i)(&gt;)", ">");

            id = id.replaceAll("(?i)(')", "''");      

            sql.append("SELECT `todo_id`,`todo_text`,`finished`,`upload_date` FROM `todo` WHERE user_id = '" + id + "'");

            System.out.println(sql);

            pstmt = conn.prepareStatement(new String(sql));

            pstmt.execute();

            rset = pstmt.executeQuery();

            request.setAttribute("print", rset);

            request.getRequestDispatcher("/member.jsp").forward(request, response);
           
            rset.close();
            pstmt.close();
            conn.close();
            return true;

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                conn.close();
            } catch (Exception e) {
            }
        }
    }

・Todo.jspにキャンセルボタンが失効しました。
問題点:値を二回でエンコードしました。
解決方法:もう一度文字列を置換して、正常な値を戻します。
<%
    userid = userid.replaceAll("(?i)(&amp;)", "&");
    userpassword = userpassword.replaceAll("(?i)(&amp;)", "&");
%>

・日時機能をServletに遷移する方法がわかりません。
member.jspにResultSetで定義した値をもらって、JSPに値をStringで変換して、結果が表示されます。
私ができると思う方法はResultSetで定義した値を変わります。しかし、この方法で実行すると、DataBaseの値も変わります。

・ArrayでResultSetの型から値を変換します。
実行方法:日時機能がBeansに遷移しました。そして、arrayで値をもらって、member.jspに渡します。
問題点:arrayの長さは定義しなければなりません。しかし、whileでDataBaseからもらって、いくつの資料がわかりません。ループが終わった前に、長さがわかることができません。もし、arrayの中にnullがあるなら、ページが真白になってしまいました。
//赤いところは問題点
String array_todo_text = new String[2];
String
array_upload_date = new String[2];
String array_todo_id = new String[2];
int counter = 0;
while (rset.next()) {
String todo_text = rset.getString("todo_text");
todo_text = todo_text.replaceAll("(?i)(&)", "&amp;");
todo_text = todo_text.replaceAll("(?i)(')", "&#039;");
todo_text = todo_text.replaceAll("(?i)(\")", "&quot;");
todo_text = todo_text.replaceAll("(?i)(<)", "&lt;");
todo_text = todo_text.replaceAll("(?i)(>)", "&gt;");

array_todo_text[counter]=todo_text;

String upload_date = rset.getString("upload_date");
upload_date = upload_date.replaceFirst("(?i)(-)", "年");
upload_date = upload_date.replaceFirst("(?i)(-)", "月");
upload_date = upload_date.replaceFirst("(?i)( )", "日");
upload_date = upload_date.substring(0,16);

int YEAR = Integer.parseInt(upload_date.substring(0,4));
int MONTH = Integer.parseInt(upload_date.substring(5,7));
int DATE = Integer.parseInt(upload_date.substring(8,10));
MONTH = MONTH-1;
DATE = DATE-1;

String
week = new String[7];
    week[0] = "日";
    week[1] = "月";
    week[2] = "火";
    week[3] = "水";
    week[4] = "木";
    week[5] = "金";
    week[6] = "土";

    Calendar YEAR_MONTH_DATE = Calendar.getInstance();
    YEAR_MONTH_DATE.set( Calendar.YEAR,YEAR );
    YEAR_MONTH_DATE.set( Calendar.MONTH,MONTH );
    YEAR_MONTH_DATE.set( Calendar.DAY_OF_MONTH,DATE );
    int DAY_OF_WEEK = YEAR_MONTH_DATE.get( Calendar.DAY_OF_WEEK );
   
    upload_date = upload_date.substring(5,11) + "(" + week[DAY_OF_WEEK]+ ")" + upload_date.substring(11,16);
   
    array_upload_date[counter]=upload_date;
   
    array_todo_id[counter]=rset.getString("todo_id");
   
    counter++;
}

Arraylistの使用
上記問題の解決方法:Arraylistで値をもらって、最後にarrayに渡します。

    List<String>list_todo_text = new ArrayList<>();
    List<String>list_upload_date = new ArrayList<>();
    List<String>list_todo_id = new ArrayList<>();

    while (rset.next()) {
    String todo_text = rset.getString("todo_text");
    todo_text = todo_text.replaceAll("(?i)(&)", "&amp;");
    todo_text = todo_text.replaceAll("(?i)(')", "&#039;");
    todo_text = todo_text.replaceAll("(?i)(\")", "&quot;");
    todo_text = todo_text.replaceAll("(?i)(<)", "&lt;");
    todo_text = todo_text.replaceAll("(?i)(>)", "&gt;");
   
    list_todo_text.add(todo_text);
   
    String upload_date = rset.getString("upload_date");
    upload_date = upload_date.replaceFirst("(?i)(-)", "年");
    upload_date = upload_date.replaceFirst("(?i)(-)", "月");
    upload_date = upload_date.replaceFirst("(?i)( )", "日");
    upload_date = upload_date.substring(0,16);
   
    int YEAR = Integer.parseInt(upload_date.substring(0,4));
    int MONTH = Integer.parseInt(upload_date.substring(5,7));
    int DATE = Integer.parseInt(upload_date.substring(8,10));
    MONTH = MONTH-1;
    DATE = DATE-1;
   
    String week = new String[7];
    week[0] = "日";
    week[1] = "月";
    week[2] = "火";
    week[3] = "水";
    week[4] = "木";
    week[5] = "金";
    week[6] = "土";

    Calendar YEAR_MONTH_DATE = Calendar.getInstance();
    YEAR_MONTH_DATE.set( Calendar.YEAR,YEAR );
    YEAR_MONTH_DATE.set( Calendar.MONTH,MONTH );
    YEAR_MONTH_DATE.set( Calendar.DAY_OF_MONTH,DATE );
    int DAY_OF_WEEK = YEAR_MONTH_DATE.get( Calendar.DAY_OF_WEEK );
   
    upload_date = upload_date.substring(5,11) + "(" + week[DAY_OF_WEEK]+ ")" + upload_date.substring(11,16);
   
    list_upload_date.add(upload_date);
   
    list_todo_id.add(rset.getString("todo_id"));
   
    }
    String todo_text=(String)list_todo_text.toArray(new String[0]);
    String
upload_date=(String)list_upload_date.toArray(new String[0]);
    String
todo_id=(String)list_todo_id.toArray(new String[0]);


最後のArrayListがArrayに変換する理由はJSPに定義した型がわからないので、Arrayに変換しました。
    String todo_text = (String) request.getAttribute("todo_text");
    String upload_date
= (String) request.getAttribute("upload_date");
    String todo_id
= (String[]) request.getAttribute("todo_id");   

プログラミング中、あった問題 10

・変数statusの使用
変数statusがerror_statusに変わりました。
変数messageがerror_messageに変わりました。
新しい変数resultを追加しました。

if (result == true && mode.equals("user_verification")
|| result == true && mode.equals("delete_Todo_database")
|| result == true && mode.equals("add_Todo_database")
|| result == true && mode.equals("edit_Todo_database"))


・if...else if...else...確実にelseで終了
以前:全部のelse ifをifに変わりました。
現在:elseで終了しました。

if (userid.equals("") && userpassword.equals("")) {
error_status = "ログイン失敗しました。";
error_message = "USERNAMEとPASSWORDを入力してください。";
}
else if (userid.equals("")) {
error_status = "ログイン失敗しました。";
error_message = "USERNAMEを入力してください。";
}
else if (userpassword.equals("")) {
error_status = "ログイン失敗しました。";
error_message = "PASSWORDを入力してください。";
}else {
String value = shain.verificationData();
if (value.equals("false")) {
error_status = "ログイン失敗しました。";
error_message = "USERNAMEもしくはPASSWORDは正しくありません。";
}
else if (value.equals("disconnect")) {
error_status = "DataBase接続できません。";
error_message = "管理者に連絡してください。";
}
else {
result = true;
}
}


・Encodeの部分UserBeansに移動します。
public String getPassword() {
password = password.replaceAll("(?i)(&)", "&amp;");
password = password.replaceAll("(?i)(')", "&#039;");
password = password.replaceAll("(?i)(\")", "&quot;");
password = password.replaceAll("(?i)(<)", "&lt;");
password = password.replaceAll("(?i)(>)", "&gt;");
return password;
}
public String getId() {
id = id.replaceAll("(?i)(&)", "&amp;");
id = id.replaceAll("(?i)(')", "&#039;");
id = id.replaceAll("(?i)(\")", "&quot;");
id = id.replaceAll("(?i)(<)", "&lt;");
id = id.replaceAll("(?i)(>)", "&gt;");
return id;
}


・userとtodoのServletが分別しました。
実行方法:Todoの機能をTodoBeansに遷移しました。ModeServletにTodoと関連した変数を変わりました。

 

・一覧画面のディスプレイ機能がDataBaseのServletに移動します。
実行方法:UserBeansにprint_todoメソッドを追加しました。

public Boolean print_todo(HttpServletRequest request, HttpServletResponse response) {
try {
ResultSet rset = null;
conn = ds.getConnection();
StringBuffer sql = new StringBuffer();

id = id.replaceAll("(?i)(')", "''");

sql.append("SELECT `todo_id`,`todo_text`,`finished`,`upload_date` FROM `todo` WHERE user_id = '" + id + "'");

System.out.println(sql);

pstmt = conn.prepareStatement(new String(sql));

pstmt.execute();

rset = pstmt.executeQuery();

request.setAttribute("print", rset);

request.getRequestDispatcher("/member.jsp").forward(request, response);

rset.close();
pstmt.close();
conn.close();
return true;

} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
conn.close();
} catch (Exception e) {
}
}
}

バグ:追加や削除や編集をしたら、真白のページに遷移してしまいました。
問題点:JSPからModeServletに値を渡します。そして、ModeServletからBeansに値を渡します。UserBeansを実行したことがないので、値がありません。ですから、TodoBeansもprint_todoメソッドを追加しなければなりません。

解決方法:UserBeansとTodoBeansがprint_todoメソッドを追加しました。


if (result == true && mode.equals("user_verification"))
{
request.setAttribute("id", userid);
request.setAttribute("password", userpassword);
user.print_todo(request, response);
}
else if(result == true && mode.equals("delete_Todo_database")
|| result == true && mode.equals("add_Todo_database")
|| result == true && mode.equals("edit_Todo_database")) {
request.setAttribute("id", userid);
request.setAttribute("password", userpassword);
todo.print_todo(request, response);
}


・for(string todo:todo_array)メソッドを使用しました。
for (String todo_array : todo) {
String todo_str = todo_array.replaceAll("(?i)(')", "''");
String sql = "DELETE FROM `company_db`.`todo` WHERE `todo_id`='" + todo_str + "'";
doDataBase(sql);

}

 

トランザクションの勉強、DataBaseで複数指令が確実に実行するためです。
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/company_db?serverTimezone=UTC&useSSL=false",
"suser", "spass");

conn.setAutoCommit(false);
Statement statement=conn.createStatement();

//Encode
id = id.replaceAll("(?i)(')", "''");

String sql1 = "delete from user where user_id=('" + id + "')";
String sql2 = "delete from todo where user_id=('" + id + "')";
statement.executeUpdate(sql1);
statement.executeUpdate(sql2);

conn.commit();
return true;

} catch (Exception e) {
e.printStackTrace();
return false;

}

問題:どうやって確認しますか?
以前の方法は一つ一つを実行するので、デバッグで止めて、一つ一つを実行しながら、DataBaseにデータを確認します。観察した結果は最初の指令を実行したら、DataBaseのデータが削除されました。現在の方法なら、全部の指令を終わる前に、DataBaseのデータが削除されません。

 

・member.jspのEncode
BeansにEncodeメソッドを追加しました。
public Boolean Encode(){
id = id.replaceAll("(?i)(&)", "&amp;");
id = id.replaceAll("(?i)(')", "&#039;");
id = id.replaceAll("(?i)(\")", "&quot;");
id = id.replaceAll("(?i)(<)", "&lt;");
id = id.replaceAll("(?i)(>)", "&gt;");
password = password.replaceAll("(?i)(&)", "&amp;");
password = password.replaceAll("(?i)(')", "&#039;");
password = password.replaceAll("(?i)(\")", "&quot;");
password = password.replaceAll("(?i)(<)", "&lt;");
password = password.replaceAll("(?i)(>)", "&gt;");
return true;
}