特殊时期,大家一定要保重身体。增强自身免疫力,一切都会过去,一起加油!!!

Apex+VisualforceでAccountオブジェクトのCRUDとページングクエリー精確検索、曖昧検索(006)

Salesforce zchao 1349℃ 0评论

Accountレコードに対して、精确查询、模糊查询を実現したいと思います。

精確検索というのは、完全に一致的なレコード名を入力しながら、検索いたします。

曖昧検索というのは、部分的なレコード名を入力しながら、検索いたします。SOQLのLIKE通りに、% Name % など。

最終的な画面イメージ

取引先名と種別も入力するって検索できる仕様、曖昧検索と精確検索ボタン、データクリアボタン

二つとも空でない、最低2文字を入力する、「%」は入力する場合、検索できず制限(SQLインジェクションを防ぐ)

SQLインジェクション:

https://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3

曖昧検索:(取引先名も曖昧&&種別も曖昧、同時成立)

①何も入力しない

 

②「%」を含む

③1文字を入力する

④正常に入力する、レコードなし場合

⑤正常に入力する、レコードある場合

⑥「クリア」ボタンを押下する

 

精確検索:(取引先名と種別とも当てる場合)

①何も入力しない

②1文字を入力する

③正常に入力する、レコードなし場合

④正常に入力する、レコードある場合

⑤「クリア」ボタンを押下する(精確検索の⑥と同じ)

 

Visualforce1.vfp

<apex:page controller="Apex1" showHeader="false">
   <script>
        function doDeleteJs(accid) {
            if (window.confirm("削除してよろしいでしょうか。")) {
                doDeleteFn(accid);
            }
        }
         function doEditJs(accid) {
           var uuu="./EditAccountList_PAGE?core.apexpages.request.devconsole=1&Id="+accid;
             window.location.href =uuu;
        }
    </script>
 <style type="text/css">
   /* footer右へ表示*/
   .footer{
     text-align: right;
   }
 </style>
   <apex:sectionHeader subtitle="Account表示一覧" title="Account"/>
   <!-- <apex:include pageName="NewAccountList_PAGE"/> -->
   <!-- <apex:include pageName="AddAccountPage"/> -->
       <apex:form id="formId2">
       <apex:pageMessages id="message2"/>
         <apex:pageBlock title="Add Account">
            <apex:pageBlockButtons >
                <apex:commandButton value="Save" action="{!save}" reRender="pageBlockTable,ttttt,formId2" />
                <apex:commandButton value="Cancel" action="{!cancel}" reRender="pageBlockTable,formId2,pb2" />
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="Account Details" columns="1" id="pb2">
                <apex:inputField value="{!act.name}" />
                <apex:inputField value="{!act.Type}"/>
                <apex:inputField value="{!act.Industry}"/>
                <apex:inputField value="{!act.Phone}"/>
            </apex:pageBlockSection>
          </apex:pageBlock>
     </apex:form>
     <apex:form id="formId">
       <apex:pageMessages id="message"/>
        <apex:actionFunction name="doDeleteFn" action="{!doDelete}" reRender="formId" >
            <apex:param name="id" value="" />
        </apex:actionFunction>
       <apex:pageBlock >
           <apex:outputText value="検索条件: " >  </apex:outputText>
           <br/><br/>
           <apex:inputText value="{!strCondName}"  id="in">取引先名:</apex:inputText>
           &nbsp;&nbsp;&nbsp;
           <apex:inputText value="{!strCondType}"  id="ou">種別:</apex:inputText>
           <br/>  <br/>
          <apex:commandButton value="曖昧検索" action="{!search}" reRender="formId,in,qqq,ppp,ooo,ou"/>
          <apex:commandButton value="精確検索" action="{!exactSearch}" reRender="formId,in,qqq,ppp,ooo,ou"/>
          <apex:commandButton value="クリア" action="{!clear}" reRender="formId,in,qqq,ppp,ooo,ou" />
      </apex:pageBlock>
      <apex:pageBlock title="検索結果(共{!count_size}レコード)" rendered="{!resultFlag}" id="qqq">
        <apex:pageblockTable value="{!accResult}" var="a"  id="ppp">
           <apex:column value="{!a.Name}" />
           <apex:column value="{!a.Type}" />
           <apex:column value="{!a.Industry}" />
           <apex:column value="{!a.Phone}" />
        </apex:pageblockTable>
      </apex:pageBlock>
     <apex:pageBlock >
       <apex:outputPanel id="showpanel">
         <apex:pageBlockTable value="{!accounts}" var="acc" footerClass="footer" id="pageBlockTable">
           <apex:column headerValue="Action"  width="70px">
                 <apex:commandLink value="" onclick="doEditJs('{!acc.Id}');" style="color:#015ba7;" id="edit" reRender="formId,message,showpanel,buttons,pageBlockTable,foo">
                     Edit
                 </apex:commandLink>
                 &nbsp;|&nbsp;
                <apex:commandLink value="" onclick="doDeleteJs('{!acc.Id}');" style="color:#015ba7;"  id="del" reRender="formId,message,showpanel,buttons,pageBlockTable,foo">
                     Del
                 </apex:commandLink>
           </apex:column>
           <apex:column headerValue="取引先名"  >
                <apex:outputlink value="https://ap2.salesforce.com/{!acc.id}" target="_blank" >{!acc.Name}</apex:outputlink>
           </apex:column>
           <apex:column value="{!acc.Type}" />
           <apex:column value="{!acc.Industry}" />
           <apex:column value="{!acc.Phone}" />
         </apex:pageBlockTable>
       </apex:outputPanel>
     </apex:pageBlock>
   </apex:form>
 </apex:page>

説明:

①<apex:inputText value=”{!strCondName}”  id=”in”>取引先名:</apex:inputText>

{!strCondName}:画面からの取引先名、取引先名の入力欄。

②<apex:commandButton value=”曖昧検索” action=”{!search}” reRender=”formId,in,qqq,ppp,ooo,ou”/>

Apexの「{!search}」メソッド名、検索処理。

③<apex:commandButton value=”クリア” action=”{!clear}” reRender=”formId,in,qqq,ppp,ooo,ou” />

Apexの「{!clear}」メソッド名、レコードと入力する値もクリア処理。

④<apex:pageBlock title=”検索結果(共{!count_size}レコード)” rendered=”{!resultFlag}” id=”qqq”>

「{!count_size}」メソッド名、レコード総数を取得。

rendered=”{!resultFlag}”:この<apex:pageBlock>が表示されるかどうかの制限、True:表示、False:非表示

https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_compref_pageBlock.htm

コンポーネントをページに表示するかどうかを指定する boolean 値。指定されていない場合、この値はデフォルトの true に設定されます。

 

Apex1.apxc

public with sharing class Apex1 {
    public List<Account> accounts;  //Account情報
    public Account act{get;set;}    //新規Account情報用
    public list<Account> accResult {get;set;}  //検索結果
    public string strCondName {get;set;}       //検索取引先名
    public string strCondType {get;set;}       //検索種別
    public boolean resultFlag {get;set;}       //検索結果表示フラグ
    public  Integer count_size;  //検索レコードの総数
    //画面に検索レコードの総数を返す
    public Integer getCount_size() {
       return count_size;
    }
    //コンストラクター
    public Apex1() {
         act = new Account(); //デフォルト New Accountオブジェクト
         resultFlag = false;  //デフォルト 検索結果一覧非表示
    }
    //変数 accounts のgetメソッド
    public List<Account> getAccounts() {
       try {
         accounts= [select Id,Name,Type,Industry,phone from Account order by createddate desc limit 50 ];
          return accounts;
       } catch (Exception e) {
          ApexPages.addMessages(e);
          return null;
       }
    }
    //精確検索
    public void exactSearch(){
         List<Account> exactSearchSOQL;
         exactSearchSOQL = [select name,id,Type,Industry,phone from Account where name=:strCondName and type=:strCondType limit 100];
         //入力した取引先名と種別との条件 判断 空でない && サイズ2を超える
          if(!String.isBlank(strCondName) && !String.isBlank(strCondType) && strCondName.length()>=2 && strCondType.length()>=2){
              if(exactSearchSOQL.size()!=0 ){
                  //検索結果一覧表示
                   resultFlag = true;
                   accResult = exactSearchSOQL;
                  //検索レコードの総数を取得
                   count_size = [select count() from Account where name like:strCondName and type like:strCondType limit 100];
               }else {
                   //system.debug('123=='+exactSearchSOQL);
                   //検索するレコード存在しない
                   resultFlag = false;
                   ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '検索条件に該当するデータがありません!'));
               }
        } else{
          //system.debug('yyyyy='+strCondName);
          //一つ空の場合
            if(String.isBlank(strCondName)|| String.isBlank(strCondType) ){
                ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '【取引先名】と【種別】を入力してください !'));
                return;
            }
          //一つサイズ 2を超えない場合、および データベースと同じレコード名
            if(strCondName.length()<2 || strCondType.length()<2){
                    ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '検索語には【取引先名】と【種別 】各2 文字以上を指定する必要があります!'));
                    ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '検索条件は完全に等しい【取引先名】と等しい【種別】を入力してください!'));
             }
      }
    }
   //曖昧検索
   public void search(){
      // flag = false;
      //String strCondName2 =  ApexPages.currentPage().getParameters().get('strCondName');
      //system.debug('99999='+strCondName);
      //if(strCondName!=null || !strCondName.equals('') || strCondName!=''){
      //system.debug('qqqqq='+strCondName);
      //sql injection   1' or '1' = '1';--   %
      //string searchQuery='select name,id,Type,Industry,phone from Account where name like \'%'+strCondName+'%\' Limit 100';
      //strCondName = strCondName;
      List<Account> searchSOQL;
       //曖昧検索 定義
       String searchName ='%'+strCondName+'%';
       String searchType ='%'+strCondType+'%';
      // String searchName2 =   ''+ strCondName+ '';
      searchSOQL = [select name,id,Type,Industry,phone from Account where name like:searchName and type like:searchType limit 100];
       //system.debug('232323==='+searchSOQL);
       //考えるプロセス
       //String soql = 'select name,id,Type,Industry,phone from Account where name like \'%%\' Limit 100';
       //SQLインジェクション=SQL Injection 対策
       //String soql = 'select name,id,Type,Industry,phone from Account where name like'+'\''+ string.escapeSingleQuotes('%'+strCondName+'%')+'\'';
       //system.debug('aaaaa='+soql);
       //system.debug('bbbbb='+strCondName);
       //system.debug(strCondName.containsAny('%'));
       //system.debug('length==='+strCondName.length());
      //入力した取引先名と種別との条件 判断 空でない && %を含まない && サイズ2を超える
       if((!String.isBlank(strCondName) && !strCondName.containsAny('%') && strCondName.length()>=2) && (!String.isBlank(strCondType) && !strCondType.containsAny('%')&& strCondType.length()>=2)){
       //if(searchQuery!=soql){
       //system.debug('6666='+strCondName);
       //if(Database.query(soql).size()!=0){
            if(searchSOQL.size()!=0){
               //検索結果一覧表示
               resultFlag = true;
               accResult = searchSOQL;
               //検索レコードの総数を取得
               count_size = [select count() from Account where name like:searchName and type like:searchType limit 100];
            }else {
               //flag  = true;
               resultFlag = false;
               //error = 'no found data';
               //system.debug('3343434==='+sq.size());
               ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '検索条件に該当するデータがありません!'));
              //system.debug('flag'+flag);
           }
         }else{
          //system.debug('yyyyy='+strCondName);
          //不満足条件な検索 メッセージ提示
          if(String.isBlank(strCondName) || String.isBlank(strCondType)){
              ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '【取引先名】と【種別】を入力してください !'));
              return;
          }
          else if(strCondName.containsAny('%') || strCondType.containsAny('%')){
              ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '「%」以外のキーワードを入力してください !'));
              return;
          }
          else if(strCondName.length()==1 || strCondType.length()==1){
              ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '検索語【取引先名】か【種別】には 2 文字以上を指定する必要があります!'));
           return;
          }
           else{
              ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.WARNING, '検索条件に該当するデータがありません!'));
              return;
          }
       }
   }
   //検索したレコードをクリア
   public void clear(){
     //検索結果一覧非表示
        resultFlag = false;
    //system.debug('111='+prds);
       if(accResult!=null){
    // system.debug('222='+prds);
    //レコードをクリア
          accResult.clear();
    //入力欄もクリア
          strCondName = '';
          strCondType = '';
       }else{
          strCondName = '';
          strCondType = '';
           // error = '';
       }
   }
    //キャンセル操作、何もない、画面をリフレッシュ
    public PageReference cancel() {
        return null;
    }
    //保存ボタン押下する、呼び出しメソッド
    public PageReference save() {
        ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO, '保存しました。'));
        //system.debug('act name:' + act.name + ' = ' + act.accountNumber);
        upsert act;
        return null;
    }
    //Account削除メソッド
     public void doDelete() {
        SavePoint sp = Database.setSavepoint(); //トランザクションの制御
        try {
            String sfid = ApexPages.currentPage().getParameters().get('id');   //Visualforce1.vfpからのidを取得
            List<Account> deleteList= [select Id from Account where Id=:sfid]; //データベースと合わせて
            if (deleteList.size() == 0) {
                ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR, 'すでに削除されました。'));
            } else {
                delete deleteList;
                ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.INFO, '削除しました。'));
              accounts= [select Id,Name,Type,Industry,phone from Account order by createddate desc limit 50 ];   //レコード更新
            }
        } catch(exception ex) {
            system.debug('Error:'+ex.getMessage());
            ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.ERROR, ex.getMessage()));
            Database.rollback(sp);  //savepoint の生成時点と同じ状況にデータベースを復元
        }
    }
}

説明:

①getCount_size()

count_size = [select count() from Account where name like:strCondName and type like:strCondType limit 100];

count() :レコードの総数を計算

https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm

②exactSearch()

精確検索 流れ:

画面からの 取引先名と種別をデータベース中に検索処理、満足条件と不満足条件 判断、できる場合、検索結果に値を格納して、

検索レコードの総数を取得し、できない場合、メッセージ提示など、詳細は写真通りです。

③search()

曖昧検索 流れ:

曖昧検索 定義
       String searchName =’%’+strCondName+’%’;
       String searchType =’%’+strCondType+’%’;

画面からの 取引先名と種別をデータベース中に検索処理、満足条件と不満足条件 判断、できる場合、検索結果に値を格納して、

検索レコードの総数を取得し、できない場合、メッセージ提示など、詳細は写真通りです。
④clear()
検索したレコードと入力した値もクリアする。
SQLインジェクションについて、
普通ですが、このような「123′ or ‘1’=’1」とか「123′ or 1=1 #」キーワードで検索したら、どうでしょうか?
例えば、ユーザー名とパスワードを入力する
select id,name,password from users where username='123' or '1'='1' and password='123' or '1'='1
ほらほら、2つのorステートメントは、前と後の2つの判断を常にtrueにして、正常にログインできるようにします。
select id,name,password from users where username='123' or 1=1 #' and password='123' or 1=1 #'
#次の内容は無視されるため、上記のステートメントは同等です(実際、パスワードボックスに何も入力しないのと同じです)。
select id,name,password from users where username='123' or 1=1 

md5暗号化およびその他のテクノロジーに対応したほうがいいと思います。

 

今回の「%」に対してちょっと説明させて頂きたいと思います。

もしかして、APEXの中に「%」の判断がない場合、検索結果はどうなっているのか?

これを見てみましょう。

もともと:
select name,id,Type,Industry,phone from Account where name like:searchName and type like:searchType limit 100

もし、strCondName とstrCondType はすべて「%」で入力する、

select name,id,Type,Industry,phone from Account where  like:% and  like:% limit 100

実際の検索結果:

nameの値あるとtypeの値あるのレコードはすべて検索できるように。これは予想以外だと思います。

select name,id,Type,Industry,phone from Account where name=’%’ and type=’%’ limit 100

よく注意してくださいませね。

 

以上となります。

何か問題がございましたら、コメントを頂れば幸せです。

 

转载请注明:zchao博客之家 » Apex+VisualforceでAccountオブジェクトのCRUDとページングクエリー精確検索、曖昧検索(006)

喜欢 (1)or分享 (0)

您必须 登录 才能发表评论!