【Go】Echoで404ページと500ページを表示

Echoを使っていてデフォルトのままで存在しないURLにアクセスするとNotFoundのJSONがレスポンスとして返される。
今回はAPIでなくてサイトを作りたかったのでHTMLを返したかった。

ちょっとやり方がわからなかったので今回は以下のように対応した。

Echoで定義されているHTTPErrorHandlerを上書きすることでハンドリングできたのでここでHTTPステータスをみてテンプレートを切り替えるように対応してみた

server.go

package main

import (
  "io"
  "strconv"
  "errors"
  "net/http"
  "html/template"

  "github.com/labstack/echo"
)

var NotFoundError = errors.New("NotFound")

type Template struct {
  templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
  return t.templates.ExecuteTemplate(w, name, data)
}

func main() {

  t := &Template{
    templates: template.Must(template.ParseGlob("public/views/*.html")),
  }

  e := echo.New()
  e.Use(middleware.Recover())

  e.Renderer = t

  e.HTTPErrorHandler = func(err error, c echo.Context) {
    if he, ok := err.(*echo.HTTPError); ok {
      if he.Code == 404 {
        c.Render(http.StatusNotFound,"404",nil)
      } else {
        c.Render(http.StatusInternalServerError,"500",nil)
      }
    }
  }

  ・・・

}

404エラーと500エラーのテンプレートを準備

views/404.html

{{define "404"}}
  Not Found
{{end}}

views/500.html

{{define "500"}}
  Server Error
{{end}}

こんなやり方がいいのか不明です。。。以上です

【Go】Echoでのテンプレート(html/template)の使い方メモ

はじめに

Echoでテンプレートの使い方を調べたのでメモ。

今回やりたかったことはそんな多くなくて
・URLによってテンプレートを振り分けたい
・ヘッダー等の共通テンプレートを使いまわしたい

実装

まずはメインの処理

server.go

package main

import(
  "net/http"
  "html/template"

  "github.com/labstack/echo"
)

type Template struct {
  templates *template.Template
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
  return t.templates.ExecuteTemplate(w, name, data)
}

// サイトで共通情報
type ServiceInfo struct {
  Title string
}

var serviceInfo = ServiceInfo {
  "サイトのタイトル",
}

func main() {

  t := &Template{
    templates: template.Must(template.ParseGlob("views/*.html")),
  }

  e := echo.New()

  e.Renderer = t

  e.GET("/page1", func(c echo.Context) error {
    // テンプレートに渡す値
    data := struct {
      ServiceInfo
      Content string
    } {
      ServiceInfo: serviceInfo,
      Content: "ページのコンテンツ",
    }
    return c.Render(http.StatusOK, "page1", data)
  })

  e.Logger.Fatal(e.Start(":1323"))
}

次はテンプレート。
header.htmlが各ページからよばれる共通テンプレート。
defineでテンプレート名をきめる

views/header.html

{{define "header"}}
  <h1>{{.ServiceInfo.Title}}</h1>
{{end}}

page1.htmlからheader.htmlを呼び出してる。
templateでdefineで定義したテンプレートを呼び出す

{{template "header" .}}の1番後ろの「.」で変数を渡している

view/page1.html

{{define "page1"}}
  {{template "header" .}}
  <div>{{.Content}}</div>
{{end}}

まとまりないけど以上です

【javascript】fullscreenAPIでフルスクリーン対応してみたので使い方メモ

特定の要素をフルスクリーンにしてくれるAPI
ただ端末によってできたりできなかったりなので対応可否で処理を分ける必要あり。
ちなみにiOSは使えなかった。

今回使ってみてまぁよく使いそうと思ったのは以下らへん
・requestFullscreen
指定した要素をフルスクリーンにする

・cancelFullScreen
フルスクリーン解除

・fullscreenchangeイベント
フルスクリーンにしたときと解除したときに発生するイベント。

フルスクリーンにする

function startFullScreen(elm) {
    if (elm.webkitRequestFullscreen) {
        elm.webkitRequestFullscreen();
    } else if (elm.mozRequestFullScreen) {
        elm.mozRequestFullScreen();
    } else if (elm.msRequestFullscreen) {
        elm.msRequestFullscreen();
    } else if (elm.requestFullscreen) {
        elm.requestFullscreen();
    } else {
        return;
    }
}

フルスクリーン解除

function endFullScreen() {
    if (document.webkitCancelFullScreen) {
        document.webkitCancelFullScreen();
    } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
    } else if (document.msExitFullscreen) {
        document.msExitFullscreen();
    } else if(document.cancelFullScreen) {
        document.cancelFullScreen();
    } else if(document.exitFullscreen) {
       document.exitFullscreen();
   }
}

フルスクリーンの変更監視

var trrigerFullscreenChange = function() {
    // do something・・・
}
document.addEventListener("webkitfullscreenchange", trrigerFullscreenChange);
document.addEventListener("fullscreenchange", trrigerFullscreenChange);
document.addEventListener("mozfullscreenchange", trrigerFullscreenChange);
document.addEventListener("msfullscreenchange", trrigerFullscreenChange);

以上です

【Go】ログ出力先をファイルに変更 - echo logger

マニュアルにあったとおりだけどメモメモ

package main

import (
  "os"
  "net/http"

  "github.com/labstack/echo"
  "github.com/labstack/echo/middleware"
)

func main() {
  e := echo.New()

  fp, err := os.OpenFile("/path/to/log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  if err != nil {
    panic(err)
  }

  e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
    Output: fp,
  }))

  ・・・
}

以上です

【swift】iosで画面の回転を検知してUITableViewを再描画する

はじめに

今回やりたかったのは画面一杯にUITableViewをセット。
端末の向きが変更されたら画面サイズに合わせてUITableViewの幅と高さを更新。ということ

なにも対応しないと縦向きから横向きにしたときにテーブルの幅が半分くらいになってしまうので対応が必要

実装

class SampleViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setView()
    }

    func setView() {
        tableView = UITableView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
        tableView.delegate = self
        tableView.dataSource = self
        view.addSubview(tableView)
    }

    // 端末の向き変更を検知                                                                                                                                                                                        
    override func viewDidAppear(_ animated: Bool) {
        NotificationCenter.default.addObserver(self, selector: #selector(self.onOrientationChange(notification:)),name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
    }

    // 向きが変わったらframeをセットしなおして再描画                                                                                                                                                               
    func onOrientationChange(notification: NSNotification){
        tableView.frame.size = CGSize(width: view.frame.width, height: view.frame.height)
        tableView.setNeedsDisplay()
        tableView.reloadData()
    }

    ・・・
}

これでやりたいことはできた。
以上です

【swift】SWTableViewCellでボタンとテキストが重なったときの対応メモ

テーブルビューのセルをスワイプしたら削除ボタンが出てくるメールアプリみたいなUI。
これを簡単に実現できるライブラリでSWTableViewCellというのがあった。

で、使い方自体はわかりやすくて簡単だったんだけどUITableViewCellの中身がスライドしないで
削除ボタンとセルの中身が重なってしまうというのがあった。

そんなことで悩んでいる人はいなくてなかなか意味がわからなかったのだが、テーブルビューの使い方に問題があった。
結論としてはSWTableViewCellをカスタムして作っていたのだがそれの中身が問題だった

class SampleTableViewCell: SWTableViewCell {

    var label = UILabel()

    override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    func setup() {
        // UITableViewCellに直接addSubviewしていた!!                                                                                                                                                     
        // addSubview(label)                                                                                                                                                                                       

        // contentViewにaddSubviewするのが本来のやりかただった!!                                                                                                                                  
        contentView.addSubview(label)
    }

    ・・・
}

基本がまだまだわかってないです。。
以上です

【swift】uiscrollviewを更新する方法メモ

はじめに

今回やりたかったことは以下
・UIScrollViewの中にUILabelをもつ
・UILabelのテキストにはAPIから取得した値をセットする
・テキストの文字数が多いのでUIScrollViewの高さをセットしてテキスト全体がみれるようにする

今まではUITableViewのヘッダーを利用してreloadData()していた。
が、0行なのにテーブルビュー使うのはもちろん無駄なのでUIScrollViewを使ってみることにした。

実装

import UIKit

class DocumentDetailViewController: BaseViewController {

    var scrollView: UIScrollView!
    var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        callApi()
        setView()
    }

    func setView() {
        scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))

        label = UILabel()
        label.font = UIFont.boldSystemFont(ofSize: 13)
        label.numberOfLines = 0

        view.addSubview(scrollView)
    }

    func callApi() {
        // 本来はAPIから取得した値をセット                                                                                                                                                             
        // ここでは3秒後に処理を行う形としている                                                                                                                                                         
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(3)) {
            self.adjustScrollView(description: contents["description"] as! String)
        }
    }

    func adjustScrollView(content: String) {
        // UILabelの高さをもとめる                                                                                                                                                                         
        label.text = content
        let rect = label.sizeThatFits(CGSize(width: scrollView.frame.width-(5*2), height: 99999))
        label.frame = CGRect(x: 5, y: 5, width: rect.width, height: rect.height)
        scrollView.addSubview(label)
        // UILabelの高さからUIScrollViewの高さを決定してセット                                                                                                                                                     
        scrollView.contentSize = CGSize(width: rect.width, height: rect.height + 5)
    }
}

このやり方が正解かわからないけどとりあえずやりたいことはできた。
以上です