Todoのまとめ

・Todoサービスのまとめ

Dependency Injection: 依存性の注入
・thymeleaf(たいむりーふ)の依存
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Hibernateを使えるようになるための依存
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

・データベースの連結の依存
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

YAMLでデータベースの設定
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/todo?characterEncoding=UTF-8&serverTimezone=JST
    driverClassName: com.mysql.cj.jdbc.Driver
    username: root
    password: root
  jpa:
    database: MySQL
    show-sql: true
    hibernate:
     naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy

・画面遷移の設定
ボタンを押すと、指定画面に遷移しもす。
@Controller
public class PageController {

    @RequestMapping("/other")
    public String other() {
        return "redirect:/";
    }

    @RequestMapping("/jump_to_add")
    public String add() {
        return "redirect:/add";
    }

    @RequestMapping("/edit/other")
    public String delete() {
        return "redirect:/";
    }
}

・時間の取得
Controllerの最初定義すると、時間の更新はサーバの起動時間になってしまいました。
ですから、新しいクラスを作成します。
public class Get {
    public static String time() {
     Timestamp timestamp = new Timestamp(System.currentTimeMillis());
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     String time = sdf.format(timestamp);
     return time;
    }
}

・Todo画面
repository.findAllは全てのデータを取得します。
そして、mav.addObjectで値を保存します。

@RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView index(@ModelAttribute TodoData tododata, ModelAndView mav) {
        mav.setViewName("index");
        Iterable<TodoData> list = repository.findAll();
        mav.addObject("datalist", list);
        return mav;
    }

追加画面へ遷移します。
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView add(ModelAndView mav) {
        mav.setViewName("add");
        return mav;
    }

Getクラスで時間をもらって、時間を設定して、データを保存します。
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @Transactional(readOnly = false)
    public ModelAndView upload(@ModelAttribute TodoData tododata, ModelAndView mav) {
        tododata.setCreatedDate(Get.time());
        tododata.setUploadDate(Get.time());
        repository.saveAndFlush(tododata);
        return new ModelAndView("redirect:/");
    }

編集画面に遷移して、テキストのIDを検索して、検索結果を保存します。
    @RequestMapping(value = "/edit/{todoid}", method = RequestMethod.GET)
    public ModelAndView edit(@ModelAttribute TodoData tododata, @PathVariable int todoid, ModelAndView mav,
            String created_date, String user_id) {
        mav.setViewName("edit");
        Optional<TodoData> data = repository.findById*1;
        return mav;
    }

Getクラスで時間をもらって、時間を設定して、データを保存します。
    @RequestMapping(value = "/edit", method = RequestMethod.POST)
    @Transactional(readOnly = false)
    public ModelAndView update(@ModelAttribute TodoData tododata, ModelAndView mav) {
        tododata.setUploadDate(Get.time());
        repository.saveAndFlush(tododata);
        return new ModelAndView("redirect:/");
    }

*1:long) todoid);
        mav.addObject("formModel", data.get(

Spring 13

・複数削除の画面を現します。
public static String todo_text(TodoData mydata) {
// get todoID & todoText
String multiple = mydata.getMultiple();
multiple = multiple.replaceAll(",", "");
// convert to String array
String
array_string = multiple.split("&split;%");
//put todoText to new array
int counter = array_string.length / 2;
String array_long = new String[counter];
int c = 1;
for (int i = 0; i < counter; i++) {
array_long[i] = array_string[c];
c = c + 2;
}
return array_long;
}

public static Long
todo_id(TodoData mydata) {

// get todoID & todoText
String multiple = mydata.getMultiple();
// convert to String array
String array_string = multiple.split("&split;%");
// convert to long array
// method needs the long value
int counter = array_string.length / 2;
Long
array_long = new Long[counter];
int c = 0;
for (int i = 0; i < counter; i++) {
array_long[i] = Long.valueOf(array_string[c]);
c = c + 2;
}
return (Long[]) array_long;
}

・完了ボタンを追加しました。
<script th:inline="javascript">
function changeUnderline(todoID) {
var btn_obj = document.getElementById(todoID + "id");
var text_obj = document.getElementById(todoID + "text");

if (text_obj.style.textDecoration == "line-through") {
text_obj.style.textDecoration = "none";
btn_obj.value = "完了";
} else {
text_obj.style.textDecoration = "line-through";
btn_obj.value = "未完了";
}
}

Spring 12

・複数削除機能を追加しました。
TodoIDの型をStringに変換するなら、複数の値をもらえるようになりましたが、
削除のメソッドを実行する時にバグになってしまいました。
ですから、新しいColumnを作成しました。
このColumnは何も保存していません。
(DataBaseと同じクラスですから、DataBaseで新しいColumnを作成しなければなりません。)
別のクラスを作成するなら、DataBaseで新しいColumnを作成するのは、
必要がなくなると思います。


複数TodoIDを受けるために、DataBaseで新しいColumnを作成しました。
TodoData.java
    @Column(nullable = true)
    private String multiple;
    public String getMultiple() {
        return multiple;
    }

    public void setMultiple(String multiple) {
        this.multiple = multiple;
    }


メソッドを使えるために、Stringの型からLongの型に変換しました。   
MultipleDelete.java
    public static Long todo_id(TodoData mydata) {
        //get todoID
        String multiple = mydata.getMultiple();
        //convert to String array
        String
array_string = multiple.split(",");
        //convert to long array
        //method needs the long value
        Long array_long = new Long[array_string.length];
        for (int i = 0; i < array_string.length; i++) {
            array_long[i] = Long.valueOf(array_string[i]);
        }
        //return value
        return (Long
) array_long;
    }
  

 
複数削除の実行   
TodoController.java
public ModelAndView removeconfirm(TodoData mydata,ModelAndView mav) {
    LongtodoID = MultipleDelete.todo_id(mydata);
        for(long delete_counter : todoID) {
        repository.deleteById(delete_counter);
    }
}

・日時の型の変換


変換したの日時をHTMLに渡します。
TodoController.java
public ModelAndView index(@ModelAttribute("formModel") TodoData mydata, ModelAndView mav) {
        mav.setViewName("index");
        Iterable<TodoData> list = repository.findAll();
        ArrayList<String> Convert_Date = new ArrayList<>();
        Convert_Date = DateConvert.Date(list,Convert_Date);
        mav.addObject("datalist", list);
        mav.addObject("Date",Convert_Date);
        return mav;
    }


日時の変換です。
DateConvert.java
    public static ArrayList<String> Date(Iterable<TodoData> list,ArrayList<String> Convert_Date) {
        for(TodoData s : list){

            String upload_date = s.getUploadDate();
            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);

            Convert_Date.add(upload_date);
        }
        return Convert_Date;
    }

Spring 12

・H2のデータ
保存することができますが、プロジェクトを再起動する時にデータを消してしまいました。
テーブルが突然なくなった状況もあります。

・データをprivateで定義することができません。
原因:Springの使い方ので、underlineを使えません。(DataBaseから値をもらうクラス)

・URLが疑問符を付いています。
template
<a href="edit.html" th:href="@{/edit/(${obj.todoID})">profile</a>
結果:
localhost:8080/edit/?123 (123はobj.todoID)

疑問符を使いたくない場合
<a href="edit.html" th:href="@{/edit/} + ${obj.todoID}">
結果:
localhost:8080/edit/123 (123はobj.todoID)

Spring 11

HSQLDBのデータが表示されません。

・新しいプロジェクト作成(H2と接続)

application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:tcp://localhost/c:/workspace/JDBC/demo
spring.datasource.username=username
spring.datasource.password=password

pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>

@Service
このクラスをサービスとして登録するためのアノテーションです。


AjaxでMyDataを取り出し、表示させます。

ページロード時にAjax通信します。
$(document).ready(function(){
var num = /*[[${param.id[0]}]]*/;
$.get("/rest/" + num, null, callback);
});

Ajax通信後の処理
function callback(result){
$('#obj').append('<li>id: ' + result.id + '</li>');
$('#obj').append('<li>name: ' + result.name + '</li>');
$('#obj').append('<li>mail: ' + result.mail + '</li>');
$('#obj').append('<li>age: ' + result.age + '</li>');
$('#obj').append('<li>memo: ' + result.memo + '</li>');
}

XMLでデータを取得します。
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>


MyData.java
import javax.xml.bind.annotation.XmlRootElement:
@XmlRootElement

 

ApplicationArguments
アプリケーションが実行された時に渡された引数を管理します。

getNonOptionArgs
アプリケーション実行時の引数をListとして取り出せます。


・Beanクラスを作成して、Beanを登録して利用します。
public class MyDataBean {

@Autowired
MyDataRepository repository;

public String getTableTagById(Long id){
Optional<MyData> opt = repository.findById(id);
MyData data = opt.get();
String result = "<tr><td>" + data.getName()
+ "</td><td>" + data.getMail() +
"</td><td>" + data.getAge() +
"</td><td>" + data.getMemo() +
"</td></tr>";
return result;
}

}

MyBootAppConfig.java
@Configuration
public class MyBootAppConfig {

@Bean
MyDataBean myDataBean(){
return new MyDataBean();
}
}


IDによって表示します。
@Autowired
MyDataBean myDataBean;

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ModelAndView indexById(@PathVariable long id,
ModelAndView mav) {
mav.setViewName("pickup");
mav.addObject("title","Pickup Page");
String table = "<table>"
+ myDataBean.getTableTagById(id)
+ "</table>";
mav.addObject("msg","pickup data id = " + id);
mav.addObject("data",table);
return mav;
}

・ページネーション
データの一部分だけを取り出して、表示します。

Repository
public Page<MyData> findAll(Pageable pageable);

Controller
@RequestMapping(value = "/page", method = RequestMethod.GET)
public ModelAndView index(ModelAndView mav, Pageable pageable) {
mav.setViewName("index");
mav.addObject("title","Find Page");
mav.addObject("msg","MyDataのサンプルです。");
Page<MyData> list = repository.findAll(pageable); //●
mav.addObject("datalist", list);
return mav;
}

表示する方:localhost:8080/page?size=2&page=0

 

・Thymeleafの独自タグを作成しました。

AttributeTagProcessorクラスを使います。

ITemplateContext
テンプレートのコンテキストを扱います。
IProcessableElementTag
エレメントタグを扱うクラスです。
AttributeName
属性名を扱うクラスです。
IElementTagStructureHandler
エレメントの構造をハンドリングします。

 

Spring 10

エンティティの連携


・HeidiSQLに連結することができません
org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: java.sql.SQLSyntaxErrorException: Table 'test_01.mydata_msgdatas' doesn't exist

・H2やHSQLDBで実行します。

HSQLDB
1.C:\Users\admin\Downloads\hsqldb-2.4.1\hsqldb\bin に移動して、runServer.batを実行します。(閉じると、実行できません。)

2.CMDで開いて、C:\Users\admin\Downloads\hsqldb-2.4.1\hsqldb\data に移動します。

3.>java -cp ..\lib\hsqldb.jar org.hsqldb.util.DatabaseManager 入力します。


DataBase配置

mydata
CREATE TABLE TEST_TABLE (
  id    INTEGER NOT NULL IDENTITY,
  name VARCHAR(256),
  mail VARCHAR(256),
  age INTEGER,
  memo VARCHAR(200)
)

msgdata
CREATE TABLE TEST_TABLE (
  id    INTEGER NOT NULL IDENTITY,
  title VARCHAR(256),
  message VARCHAR(256),
)


Spring配置

application.properties
spring.datasource.url=jdbc:hsqldb:file:./db/testdb;shutdown=true
spring.jpa.hibernate.ddl-auto=update

pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
</dependency>

実行結果:成功


H2
会ったバグ
java. sql.SQLTransientConnectionException: java.net. ConnectException: Connection refused: connect
解決できませんでしたが、HSQLDBでDateBaseを作ったら、突然使えるようになりました。

Spring 09

・メソッドチェーン
メソッドの呼び出しを連続して記述する手法です。
例:
entityManager.createQuery(qstr).setParameter("fid", fid)
.setParameter("fname", "%" + fstr + "%").setParameter("fmail", fstr + "@%")


@NamedQuery
クエリー文に名前を付けてエンティティクラスに用意しておきます。

@NamedQueries
複数のクエリー文を作りたい時、このアノテーションを使って全てをまとめることができます。


・Criteria APIによる検索

1.CriteriaBuilderの取得
CriteriaBuilderインスタンスの用意です。

CriteriaBuilder builder=《EntityManager》.getCriteriaBuilder();

 

2.CriteriaQueryの作成
特定のエンティティにアクセスするには、そのエンティティのclassプロパティを引数に指定します。

CriteriaQuery<エンティティ> 変数 = 《CriteriaBuilder》.createQuery(エンティティ.class);

 

3.Rootの取得
CriteriaBuilderのformメソッドでRootを取得します。引数には、検索するエンティティのClassを指定します。

Root<エンティティ> 変数 = 《CriteriaBuilder》.from(エンティティ.class);

4.createQueryして結果を取得

createQueryでQueryを生成し、getResultListで結果のListを取得します。

List<エンティティ> 変数 = (List<エンティティ>)《EntityManager》.createQuery(《CriteriaBuilder》).getResultList();


全要素の検索
    @Override
    public List<MyData> getAll() {
        List<MyData> list = null;       
        CriteriaBuilder builder =
                entityManager.getCriteriaBuilder();
        CriteriaQuery<MyData> query =
                builder.createQuery(MyData.class);
        Root<MyData> root = query.from(MyData.class);
        query.select(root);
        list = (List<MyData>)entityManager
                .createQuery(query)
                .getResultList();
        return list;
    }
   
名前の検索
    @Override
    public List<MyData> find(String fstr){
        CriteriaBuilder builder =
                entityManager.getCriteriaBuilder();
        CriteriaQuery<MyData> query =
            builder.createQuery(MyData.class);
        Root<MyData> root =
            query.from(MyData.class);
        query.select(root)
            .where(builder.equal(root.get("name"), fstr));
        List<MyData> list = null;
        list = (List<MyData>) entityManager
                .createQuery(query)
                .getResultList();
        return list;
    }
 

  
CriteriaBuilder
CriteriaQueryのオブジェクトを作成します。
    
CriteriaQuery
クエリーに指定したアイテムを返します。
以前に指定された選択がある場合は、置き換えます。

Root
ルートに対応するメタモデルエンティティを返します。

昇順のorderを得ます
《CriteriaBuilder》.asc(《Expression》);

降順のorderを得ます
《CriteriaBuilder》.desc(《Expression》);

指定の位置から取得します。
Query 変数 =《Query》.setFirstResult(《int》)

指定の個数を取得します。
Query 変数 =《Query》.setMaxResult(《int》)


・エンティティの連携
@OneToMany
1つのエンティティに対して、もう一方のエンティティの複数が対応します。

@ManyToOne
複数のエンティティに対して、もう一方のエンティティの1つだけが対応します。

@ManyToMany
複数のエンティティに対して、他方の複数のエンティティが対応する関係です。