4

Primefaces コンポーネントの graphicImage で画像を表示する際に問題が発生しています。

MB が SessionScoped の場合、すべて正常に動作します。ただし、ViewScoped の場合、画像は表示されません。

私はSessionScopedを維持することができましたが、私のページは画像をアップロード/削除し、それらはPostgreSQLに保存されています(私のソフトウェアアーキテクチャは私にこれを強制しました). 問題は、新しい画像を挿入したり削除したりすると、ブラウザーを閉じて再度開くまで、ページに最後の値 (更新されていないもの) が表示されたままになることです。ViewScoped でページをリロードでき、問題が解決されることを願っています。

ページのスナップは次のとおりです。

                    <p:panel id="panelListFotoProduto" header="Fotos do Produto" toggleable="true" collapsed="false" closable="false"
                             toggleSpeed="500" widgetVar="panelListFotoProduto" visible="true" >
                        <p:dataTable id="listFotoProduto" paginatorPosition="bottom" value="#{produtoMB.listProdutoFoto}" 
                                     lazy="true" var="pf" selectionMode="single" paginator="true" rows="1"
                                     rowKey="#{pf.id}">
                            <p:column style="width: 100%" >
                                <h:panelGrid columns="1" cellpadding="4"> 
                                    <p:graphicImage id="imageProduto" value="#{produtoMB.getFoto(pf)}" onclick="dialogFotoProduto.show()"/>
                                    <p:commandButton value="Excluir" style="width: 100%;" update=":growl :formProduto:panelListFotoProduto" actionListener="#{produtoMB.removeFoto(pf)}"/>
                                </h:panelGrid>     
                            </p:column>
                            <f:facet name="footer">
                                <h:panelGrid columns="1" cellpadding="4"> 
                                    <p:commandButton value="Adicionar" style="width: 100%;" update=":growl :formProduto:panelListFotoProduto" actionListener="#{produtoMB.adicionarFoto()}"/>
                                    <h:outputText id="totalProdutos" style="font-weight:bold" value="Total de Fotos Cadastrados: #{produtoMB.listProdutoFoto.size() }"/>
                                </h:panelGrid>                                      
                            </f:facet>
                        </p:dataTable>
                    </p:panel>

ここに私のMBがあります:

@ManagedBean
@SessionScoped
public class ProdutoMB {

    private Produto       produto_atual      = new Produto();
    private Produto_Foto  produto_foto_atual = new Produto_Foto();

    private List<Produto>      listProduto         = null;    
    private List<Produto_Foto> listProdutoFoto     = null;
    private List<Produto_Foto> listProdutoFoto_all = null;

    private boolean adicionarFoto = false;
    private StreamedContent last;

    public Produto getProduto_atual(){
        return produto_atual;
    }    

    public void setProduto_atual(Produto produto) throws SQLException, IOException{        
        if(produto != null && produto_atual != null 
        && produto.getCd_produto().equals(produto_atual.getCd_produto())){
            return ;
        }
        produto_atual = produto;
        produto_foto_atual = null;        
        listProdutoFoto    = new ArrayList<>();

        int index = 0;
        System.out.println("List >> " + getListProdutoFoto_all());
        for(Produto_Foto p_f : getListProdutoFoto_all()){
            if(produto_atual.getCd_produto().equals(p_f.getCd_produto())){
                p_f.setId(index++);
                p_f.setContent(getFoto_b(produto_atual.getCd_empresa(), p_f.getCd_imagem()));
                listProdutoFoto.add(p_f);
            } 
        }

        if(listProdutoFoto.isEmpty()){
            Produto_Foto p_f = new Produto_Foto();
            p_f.setId(-1);
            p_f.setCd_produto(produto_atual.getCd_produto());
            p_f.setCd_empresa(produto_atual.getCd_empresa());
            p_f.setCd_imagem(-1);
            p_f.setContent(getFoto_b(produto_atual.getCd_empresa(), p_f.getCd_imagem()));
            listProdutoFoto.add(p_f);
        }       
    }

    public void setProduto_foto_atual(Produto_Foto produto_foto) {
        if(produto_foto != null && produto_foto_atual != null 
        && produto_foto.getCd_produto().equals(produto_foto_atual.getCd_produto())){
            return ;
        }
        produto_foto_atual = produto_foto;
    }

    public ProdutoMB(){
    }

    public void handleFileUpload(FileUploadEvent event) throws SQLException, IOException{
        if(event != null){            
            UploadedFile imagem_upload = event.getFile();

            byte[] buf = imagem_upload.getContents();
            BufferedImage image = ImageIO.read(ImageIO.createImageInputStream(new ByteArrayInputStream(buf)));            

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write( image, "jpg", baos );
            baos.flush();
            buf = baos.toByteArray();
            baos.close();            

            BufferedImage scaledImage = Scalr.resize(image, 250);

            if(scaledImage != null){
                baos = new ByteArrayOutputStream();
                ImageIO.write( scaledImage, "jpg", baos );
                baos.flush();
                byte[] imageInByte = baos.toByteArray();
                baos.close();

                buf = imageInByte;
            }

            if(adicionarFoto){
                adicionarFoto = false;

                Produto_Foto p_f = new Produto_Foto();
                p_f.setId(listProdutoFoto.size());
                p_f.setCd_produto(produto_atual.getCd_produto());
                p_f.setCd_empresa(produto_atual.getCd_empresa());
                p_f.setCd_imagem(-1);
                p_f.setContent(buf);

                if(listProdutoFoto.size() == 1){
                    Produto_Foto p_f_aux = listProdutoFoto.get(0);
                    if(p_f_aux.getId() == -1){
                        p_f.setId(0);
                        listProdutoFoto.set(0, p_f);
                    } else {
                        listProdutoFoto.add(p_f);
                    }
                } else {
                    listProdutoFoto.add(p_f);
                }
                return;
            }

            if(produto_foto_atual != null){
                int index = produto_foto_atual.getId();
                if(index >= 0){
                    produto_foto_atual.setContent(buf);
                    listProdutoFoto.set(index, produto_foto_atual);
                } else if(index == -1){
                    produto_foto_atual.setContent(buf);
                    produto_foto_atual.setId(++index);
                    listProdutoFoto.set(index, produto_foto_atual);
                }
            }
        } 
    }

    public void adicionarFoto(){
        adicionarFoto = true;
        RequestContext.getCurrentInstance().execute("dialogFotoProduto.show()");
    }

    public void removeFoto(Produto_Foto produto_foto) throws SQLException, IOException{
        if(produto_foto == null){
            return ;
        }
        int index = produto_foto.getId();
        if(index >= 0){
            listProdutoFoto.remove(index);

            for(int i = 0; i < listProdutoFoto.size(); i++){
                Produto_Foto p_f = listProdutoFoto.get(i);
                if(p_f.getId() > index){
                    p_f.setId(p_f.getId() - 1);
                }
            }
        }
        if(listProdutoFoto.isEmpty()){
            Produto_Foto p_f = new Produto_Foto();
            p_f.setId(-1);
            p_f.setCd_produto(produto_atual.getCd_produto());
            p_f.setCd_empresa(produto_atual.getCd_empresa());
            p_f.setCd_imagem(-1);
            p_f.setContent(getFoto_b(produto_atual.getCd_empresa(), p_f.getCd_imagem()));
            listProdutoFoto.add(p_f);
        }    
    }

    public void removeFotoAtual(){
        if(produto_foto_atual == null){
            return ;
        }
        int index = produto_foto_atual.getId();
        if(index >= 0){
            listProdutoFoto.remove(index);

            for(int i = 0; i < listProdutoFoto.size(); i++){
                Produto_Foto p_f = listProdutoFoto.get(i);
                if(p_f.getId() > index){
                    p_f.setId(p_f.getId() + 1);
                }
            }
        }
    }

    public void removeFotoBanco(Produto_Foto pf_aux) throws SQLException{
        if(produto_atual == null){
            return ;
        }

        if(pf_aux == null){
            return ;
        }

        Integer cd_empresa = produto_atual.getCd_empresa();

        if(cd_empresa == null){
            return ;
        }

        Connection conn = null;
        Connection conn_p = null;
        PreparedStatement ps = null;
        ResultSet rs         = null;
        try {
            conn   = conectorImagemPostgreSQL.getConnection(); 
            conn_p = conectorPostgreSQL.getConnection();
            conn.setAutoCommit(false);

            ps = conn_p.prepareStatement(" DELETE FROM produto_foto WHERE cd_empresa = ? AND cd_produto = ? AND nm_foto = ? AND cd_imagem = ?;");                        
            ps.setInt(1, cd_empresa);
            ps.setString(2, produto_atual.getCd_produto());
            ps.setString(3, pf_aux.getNm_foto());
            ps.setInt(4, pf_aux.getCd_imagem());
            ps.executeUpdate();
            ps.close();
        } catch(Exception e){
            e.printStackTrace();
        } finally{
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            conn.commit();
        }
    }

    public void salvaFotoBanco() throws SQLException{
        if(produto_atual == null){
            return ;
        }

        if(listProdutoFoto == null || listProdutoFoto.isEmpty()){
            return ;
        }

        Integer cd_empresa = produto_atual.getCd_empresa();

        if(cd_empresa == null){
            return ;
        }

        Connection conn = null;
        Connection conn_p = null;
        PreparedStatement ps = null;
        ResultSet rs         = null;

        conn   = conectorImagemPostgreSQL.getConnection(); 
        conn_p = conectorPostgreSQL.getConnection();  

        ps = conn_p.prepareStatement(" DELETE FROM produto_foto WHERE cd_empresa = ? AND cd_produto = ?;");

        ps.setInt(1, cd_empresa);
        ps.setString(2, produto_atual.getCd_produto());
        ps.executeUpdate();
        ps.close();

        conn_p.commit();

        for(Produto_Foto p_f : listProdutoFoto){                       
            try {
                conn.setAutoCommit(false);
                if(p_f.getId() >= 0 && p_f.getCd_imagem() < 0){

                    ps = conn.prepareStatement("SELECT f_sequencial('IMAGEMLO', ?) as cd_imagem");
                    ps.setInt(1, cd_empresa);
                    rs = ps.executeQuery();
                    if (rs != null) {
                        while(rs.next()) {
                            p_f.setCd_empresa(produto_atual.getCd_empresa());
                            p_f.setCd_produto(produto_atual.getCd_produto());
                            p_f.setCd_imagem(rs.getInt(1));
                        }
                    }
                    byte[] b = p_f.getContentBytes();

                    BufferedImage image = ImageIO.read(ImageIO.createImageInputStream(new ByteArrayInputStream(b)));            

                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write( image, "jpg", baos );
                    baos.flush();
                    b = baos.toByteArray();
                    baos.close();            

                    BufferedImage scaledImage = Scalr.resize(image, 250);

                    if(scaledImage != null){
                        baos = new ByteArrayOutputStream();
                        ImageIO.write( scaledImage, "jpg", baos );
                        baos.flush();
                        byte[] imageInByte = baos.toByteArray();
                        baos.close();

                        b = imageInByte;
                    }
                    LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI();
                    int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE);
                    LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);
                    obj.write(b);
                    obj.close();
                    ps = conn.prepareStatement(" INSERT INTO imagemlo(cd_empresa, cd_imagem, ds_imagem, by_imagem) "
                                                        + "VALUES (?, ?, ?, ?);");

                    String file_name = p_f.getCd_empresa() + "_" + 
                                p_f.getCd_produto() + "_" + 
                                p_f.getCd_imagem() + ".jpg";

                    ps.setInt(1, cd_empresa);
                    ps.setInt(2, p_f.getCd_imagem());
                    ps.setString(3, file_name);
                    ps.setLong(4, oid);
                    ps.executeUpdate();
                    ps.close();
                }
                ps = conn_p.prepareStatement(" INSERT INTO produto_foto(cd_empresa, cd_produto, nm_foto, cd_imagem) "
                                                    + "VALUES (?, ?, ?, ?);");

                String file_name = p_f.getCd_empresa() + "_" + 
                                p_f.getCd_produto() + "_" + 
                                p_f.getCd_imagem() + ".jpg";

                ps.setInt(1, cd_empresa);
                ps.setString(2, produto_atual.getCd_produto());
                ps.setString(3, file_name);
                ps.setInt(4, p_f.getCd_imagem());
                ps.executeUpdate();
                ps.close();
            } catch(Exception e){
                e.printStackTrace();
            } finally{
                if (rs != null) {
                    rs.close();
                }
                if (ps != null) {
                    ps.close();
                }
                conn.commit();
            }
        }
        FacesMessage msg = new FacesMessage("Alterações salvas com sucesso.", "");  
        FacesContext.getCurrentInstance().addMessage(null, msg); 
    }

    public void editaFoto(Produto_Foto produto_foto){
        if(produto_foto != null){
            produto_foto_atual = produto_foto;
        }
    }

    public StreamedContent getFotoAtual() throws SQLException, IOException{
        if(produto_foto_atual != null){
            int index = produto_foto_atual.getId();
            if(index >= 0){
                last = listProdutoFoto.get(index).getContent();
            }
        }
        return last;
    }

    public StreamedContent getFoto(Produto_Foto produto_foto) throws SQLException, IOException{
        if(produto_foto != null){
            produto_foto_atual = produto_foto;

            int index = produto_foto.getId();
            if(index >= 0){
                last = listProdutoFoto.get(index).getContent();
            }

            if(index == -1){
                last = listProdutoFoto.get(0).getContent();
            }
        }

        if(last == null){
            last = (new DefaultStreamedContent(new ByteArrayInputStream(getFoto_b(produto_atual.getCd_empresa(), -1)), "image/jpeg", "img_padrao"));
        }
        return last;
    }

    public StreamedContent getFoto(Integer cd_empresa, Integer cd_imagem) throws SQLException, IOException{
        Usuario u = (Usuario)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("LoggedUser");

        if(u == null){
            System.out.println("Usuário é nulo");
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));
            return (new DefaultStreamedContent(fis, "image/jpeg", "img_padrao"));
        }

        if(produto_atual == null){
            System.out.println("Produto Atual é nulo");
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));
            return (new DefaultStreamedContent(fis, "image/jpeg", "img_padrao"));
        }

        if(cd_empresa == null){
            System.out.println("cd_empresa é nulo");
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));
            return (new DefaultStreamedContent(fis, "image/jpeg", "img_padrao"));
        }

        if(cd_imagem == null || cd_imagem < 0){
            System.out.println("cd_imagem é nulo ou menor que zero");
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));
            return (new DefaultStreamedContent(fis, "image/jpeg", "img_padrao"));
        }

        Connection        conn = null;
        PreparedStatement   ps = null;
        ResultSet           rs = null;

        try {        
            conn = conectorImagemPostgreSQL.getConnection();  
            conn.setAutoCommit(false);
            LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI();

            ps = conn.prepareStatement("SELECT ds_imagem, by_imagem FROM imagemlo WHERE cd_empresa = ? AND cd_imagem = ?");
            ps.setInt(1, cd_empresa);
            ps.setInt(2, cd_imagem);

            rs = ps.executeQuery();
            if (rs != null) {
                while(rs.next()) {

                    String ds_imagem = rs.getString("ds_imagem");   
                    int oid = rs.getInt("by_imagem");

                    LargeObject obj = lobj.open(oid, LargeObjectManager.READ);

                    //read the data
                    byte buf[] = new byte[obj.size()];
                    obj.read(buf, 0, obj.size());
                    obj.close();

                    BufferedImage image = ImageIO.read(ImageIO.createImageInputStream(new ByteArrayInputStream(buf)));            

                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write( image, "jpg", baos );
                    baos.flush();
                    buf = baos.toByteArray();
                    baos.close();            

                    BufferedImage scaledImage = Scalr.resize(image, 250);

                    if(scaledImage != null){
                        baos = new ByteArrayOutputStream();
                        ImageIO.write( scaledImage, "jpg", baos );
                        baos.flush();
                        byte[] imageInByte = baos.toByteArray();
                        baos.close();

                        buf = imageInByte;
                    }
                    return (new DefaultStreamedContent(new ByteArrayInputStream(buf), "image/jpeg", ds_imagem));
                }
            }
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));

            return (new DefaultStreamedContent(fis, "image/jpeg", "img_padrao"));
        } finally{
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            conn.commit();
        }
    }    

    public byte[] getFoto_b(Integer cd_empresa, Integer cd_imagem) throws SQLException, IOException{
        Usuario u = (Usuario)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("LoggedUser");

        if(u == null){
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));

            ByteArrayOutputStream out = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024]; 
            while (fis.read(buffer) != -1) out.write(buffer); 

            return out.toByteArray();
        }

        if(produto_atual == null){
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));

            ByteArrayOutputStream out = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024];
            while (fis.read(buffer) != -1) out.write(buffer); 

            return out.toByteArray();
        }

        if(cd_empresa == null){
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));

            ByteArrayOutputStream out = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024]; 
            while (fis.read(buffer) != -1) out.write(buffer); 

            return out.toByteArray();
        }

        if(cd_imagem == null || cd_imagem < 0){
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));

            ByteArrayOutputStream out = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024]; 
            while (fis.read(buffer) != -1) out.write(buffer); 

            return out.toByteArray();
        }

        Connection        conn = null;
        PreparedStatement   ps = null;
        ResultSet           rs = null;

        try {        
            conn = conectorImagemPostgreSQL.getConnection();  
            conn.setAutoCommit(false);
            LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI();

            ps = conn.prepareStatement("SELECT ds_imagem, by_imagem FROM imagemlo WHERE cd_empresa = ? AND cd_imagem = ?");
            ps.setInt(1, cd_empresa);
            ps.setInt(2, cd_imagem);

            rs = ps.executeQuery();
            if (rs != null) {
                while(rs.next()) {

                    String ds_imagem = rs.getString("ds_imagem");   
                    int oid = rs.getInt("by_imagem");

                    LargeObject obj = lobj.open(oid, LargeObjectManager.READ);

                    //read the data
                    byte buf[] = new byte[obj.size()];
                    obj.read(buf, 0, obj.size());
                    obj.close();
                    BufferedImage image = ImageIO.read(ImageIO.createImageInputStream(new ByteArrayInputStream(buf)));            

                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write( image, "jpg", baos );
                    baos.flush();
                    buf = baos.toByteArray();
                    baos.close();            

                    BufferedImage scaledImage = Scalr.resize(image, 250);

                    if(scaledImage != null){
                        baos = new ByteArrayOutputStream();
                        ImageIO.write( scaledImage, "jpg", baos );
                        baos.flush();
                        byte[] imageInByte = baos.toByteArray();
                        baos.close();

                        buf = imageInByte;
                    }
                    return buf;
                }
            }
            FileInputStream fis = new FileInputStream(FacesContext.getCurrentInstance().getExternalContext().getRealPath("image_not_found.png"));

            ByteArrayOutputStream out = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024]; 
            while (fis.read(buffer) != -1) out.write(buffer); 

            return out.toByteArray();
        } finally{
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            conn.commit();
        }
    }    

    public void save() throws SQLException{
        salvaFotoBanco();
    }

    public List<Produto> getListProduto() {

        Usuario u = (Usuario)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("LoggedUser");

        if(u == null){
            return null;
        }        

        Integer cd_empresa = u.getCd_empresa();

        if(cd_empresa == null){
            return null;
        }

        if(listProduto == null){
            listProduto = getProduto(cd_empresa);
        }

        return listProduto;
    }

    public List<Produto_Foto> getListProdutoFoto_all() {
        if(listProdutoFoto_all == null){
            listProdutoFoto_all = getProduto_Foto(produto_atual.getCd_empresa());
        }
        return listProdutoFoto_all;
    }

    /**
     * Methods to get/set data in the DB...
     */
}

SessionScoped でコンテンツをリロードできれば、より良いでしょう。

助けてくれてありがとう。

私はJBOSS 7、Primefaces 3.4.2を使用しています

[]のウィリアム・バータン

4

2 に答える 2

17

<p:graphicImage>どのように動作するかを理解することが重要StreamedContentです。すべての単一の画像の意志の背後にあるプロパティは、<p:graphicImage value>基本的に 2 つの完全に別個の HTTP 要求で参照されます。

最初の HTTP リクエスト (JSF のすべての作業を行い、タグを含む一連の HTML コードの生成を担当するリクエスト<img>) は、基本的にプロパティを参照して、返される画像のタイプ ( aStringまたは a などStreamedContent)を決定します。適切な URL をインライン化/自動生成できます。StreamedContent画像の内容が読み取られていない場合はご注意ください。つまり、HTML 画像はそのようには機能しません。まったく同じ HTTP 要求でそれらをインライン化するのは Web サーバーではなく、別の HTTP 要求で個別にダウンロードするのは Web ブラウザーです。

を使用するStreamedContentと、2 番目の HTTP リクエスト (要素の URL に基づいて具体的な画像ファイルをダウンロード<img>し、HTML ドキュメント内の目的の場所に表示する必要がある場合に Web ブラウザによって起動されるもの) が基本的に参照されます。画像コンテンツをダウンロードするために、もう一度プロパティを呼び出します。

ビュー スコープ Bean は、非表示の入力フィールドによって特定の JSF ビューに結び付けられますjavax.faces.ViewState。これが HTTP リクエストに存在しない (または異なる値を持っている) 場合、基本的にはまったく異なるビューの手段があります。したがって、まったく同じビュー スコープの Bean インスタンスは、これらのイメージ リクエストに再利用されません。すべてのイメージ リクエストは、すべてのプロパティがデフォルトに設定された新しいビュー スコープの Bean インスタンスを取得します。セッション スコープ Bean は基本的に、クライアントとサーバー間で現在確立されている HTTP セッションの間存続するため、まったく同じ Bean インスタンスがそれらのイメージ リクエストに再利用されるため、そのように機能します。

具体的な問題を解決するには、アプリケーションを作成するか、リクエスト パラメータとして ID で画像を取得するスコープ Bean をリクエストするのが最善です。このようにして、一度に数十または数百の画像でセッションを汚染する必要もありません (同じ画像を複数の同時ユーザーが表示している場合にサーバーのメモリを浪費するだけです)。データテーブルのイメージ識別子のリストが必要であり、別のアプリケーション スコープ Bean によってイメージを提供するだけです。

以下も参照してください。

于 2012-11-30T20:29:10.897 に答える