SSM 統合例 - CRUD の迅速な開発

SSM 統合例 - CRUD の迅速な開発

序文

参考ビデオ: リンク: Shang Silicon Valley SSM Shang Silicon Valley SSM 実践演習丨SSM 統合 CRUD の急速な開発。
このノートを書く目的は主に、後で SSM 統合フレームワークをレビューすることですが、他の SSM プロジェクトを開発する際の参照用のテンプレートとしても使用できます。同時に、それは誰もが学ぶためでもあります。異なる意見がある場合は、交換することを歓迎します。このプロジェクトの開発環境は IDEA です。新しい Maven プロジェクトを作成する手順は、リンク: Maven プロジェクトを作成するアイデア の記事
に従ってください

1.Mavenプロジェクトを作成する

jar パッケージをインポートします。

ssm フレームワーク関連の jar パッケージ: spring-webmVC、Spring-jdbc、spring-aspects、mybatis、mybatis-spring

データベース接続ドライバー関連の jar パッケージ: c3p0、mysql

その他: jstl、サーブレット API、junit

ブートストラップ フロントエンド フレームワークの導入

webapp パッケージの下に静的パッケージを作成し、ダウンロードしたブートストラップ ファイルを静的パッケージにインポートし、index.jsp インターフェイスを作成して、ブートストラップの css スタイル ファイルと js ファイルをインポートします。

静的パッケージの下に js パッケージを作成し、ダウンロードした jquery ファイルを js パッケージにインポートし、js パッケージ内の jquery ファイルをindex.jsp ページにインポートします。

ssm 統合用の主要な設定ファイルを書き込む

Spring コンテナを開始するコードを web.xml ファイルに記述し、Spring 構成ファイルを applicationContext.xml としてロードし、リソース内に applicationContext.xml ファイルを作成します (ここでの主な構成はビジネス ロジックに関連しています)。

<!--    启动spring容器-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

すべてのリクエストをインターセプトするように web.xml で springmvc のフロント コントローラーを構成します。servlet-name の値はdispatcherServletです。WEB-INFファイル内にdispatcherServlet-servlet.xmlファイルを作成します。

<!--    SpringMVC的前端控制器,拦截所有请求-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

web.xmlで文字エンコードフィルターを設定します。アイデア検索バーで CharacterEncodingFilter クラスを検索して、クラス内のメンバー属性 encoding、forceRequestEncoding、およびforceResponseEncoding の値を utf-8、true、および true に設定できます。

<!--    字符编码过滤器,一定要放在所有过滤器之前-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

web.xml で REST スタイルの URI を構成します。

<!--    使用Rest风格的URI,将页面普通的post请求转化为指定的delete或者put请求-->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2. Spring MVCの設定

dispatcherServlet-servlet ファイルで SpringMVC を構成します。SpringMVCの設定ファイルには、Webサイトへのジャンプロジックの制御と設定が含まれています。

スキャンコントローラーのコンポーネント

    <context:component-scan base-package="com.shenshang" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

注: パッケージをスキャンするには context:component-scan タグを使用する必要があります。xml でこのタグを設定した後、Spring はベースパッケージまたはサブパッケージの下の Java ファイルを自動的にスキャンできます。@Component @Controller@ がある場合は、サービスなど。これらのアノテーション付きクラスについては、これらのクラスを Bean として登録します。 context:component-scan には use-default-filters 属性があり、デフォルトは true です。これは、指定されたパッケージの下でマークされたすべての @Component がスキャンされることを意味します。 @Componentのサブアノテーション@Serviceや@RepositoryなどをBeanとして登録します。

指定したパッケージ内のコントローラーのみをスキャンする場合は、次のコード ブロックに示すように、サブタグ context:include-filter を使用できます。

<context:component-scan base-package="tv.huan.weisp.web .controller">  

<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>   

</context:component-scan>

これは、ベースパッケージで指定された @Controller の下の Java クラスのみをスキャンし、それらを Bean として登録します。

ビューリゾルバーを構成する

オーバースキャン コントローラーを構成した後、ページ リターンを容易にするためにビュー パーサーの構成を続けます。Bean タグの class 属性値は、InternalResourceViewResolver の完全なクラス名です。property タグは Bean タグで使用できます。このタグの name 属性の値が suffix である場合、ビューのサフィックスは value 属性の値を通じて設定できます。このタグの name 属性の値が prefix である場合、ビューのプレフィックスは、value 属性値を通じて設定できます。

<!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--        视图后缀-->
        <property name="suffix" value=".jsp"></property>
<!--        试图前缀-->
        <property name="prefix" value="/WEB-INF/views"></property>
    </bean>
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
<!--    告知Spring容器,启用注解驱动,支持@RequestMapping注解,这样就可以使用@RequestMapping来配置处理器-->
    <mvc:annotation-driven></mvc:annotation-driven>

注: ビュー パーサーを設定するには、Bean タグの下のプロパティ タグを使用して、ビュー プレフィックスとビュー サフィックスを設定する必要があります。ビュー サフィックスによって返される URL 文字列 — コントローラーのメソッドによってサフィックスが追加され、 view prefix—コントローラ内のメソッド。返される URL 文字列には、このプレフィックスが追加されます。

注: mvc:default-servlet-hander タグの役割: WEB コンテナが起動すると、コンテキスト内に DefaultServletHttpRequestHandler が定義され、DispatcherServlet のリクエストが処理されます。リクエストがマッピングされている場合は、バックグラウンドに引き渡す 対応する処理プログラムがマッピングされていない場合は、対応する静的リソースを見つけるために、WEBアプリケーションサーバーのデフォルトサーブレットに引き渡されて処理され、リソースが見つかった場合のみエラーが報告されます。見つからない。

注: mvc:annotation-driven は Spring コンテナーに通知し、アノテーション駆動を有効にし、@RequestMapping アノテーションをサポートして、@RequestMapping を使用してプロセッサーを構成できるようにします。

3. スプリングの設定

applicationContext.xml で Spring を構成します。主な構成はビジネス ロジックに関連します。

データソースの構成

Bean タグを使用すると、class 属性値は comboPooledDataSource という c3p0 の完全なクラス名になります。この Bean タグでは、プロパティ タグを使用してデータ ソースの基本情報 (jdbcUrl、driverClass、ユーザー、パスワードなど) を設定し、サフィックス .properties を持つ構成ファイルをリソース パッケージの下に作成し、基本的なこのファイル内のデータ ソースの情報。同時に、xml ファイル内にプロパティの接尾辞を付けたファイルを導入する必要があり、context:property-placeholder タグを使用し、その location 属性値でプロパティのファイル パスを指定できます。

<!--    设置扫描包-->
    <context:component-scan base-package="com.shenshang.crud" use-default-filters="false">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
<!--配置数据源-->
    <context:property-placeholder location="classpath:dbconfig.properties"></context:property-placeholder>
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
    <property name="driverClass" value="${jdbc.driverClass}"></property>
    <property name="user" value="${jdbc.user}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssm_crud
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=szx...2943

注: Spring を構成するプロセスでは、スキャン パッケージをセットアップする必要があり、context:component-scan タグを使用する必要がありますが、Spring はコントローラーをスキャンしないことを除いてすべてをスキャンする必要があり、コンテキストを使用する必要があります。 :exclude-filter タグ。Use-dafault-filters=”false”の場合:context:exclude-filterで指定されたものはスキャンせず、context:include-filterで指定されたものはスキャンする

設定とMyBatisの統合

Bean タグを使用します。クラスは SqlSessionFactoryBean クラスを使用します。MyBatis グローバル構成ファイルの場所を指定するには、property タグを使用する必要があります (property タグの name 属性値は configLocation に設定され、value 属性値は に設定されます)。 mybatis設定ファイルのパス、name属性値が設定されます。dateSourceの場合、value属性値が先ほど設定したデータソース名に設定されます)、MyBatisのマッパーファイルの場所を指定します(リソースパッケージ内にマッパーパッケージを作成し、上記と同じ)。

<!--    配置和MyBatis的整合-->
<bean id="SqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="configLocation" value="classpath:mybatis-config.xml"></property>
    <property name="dataSource" ref="pooledDataSource"></property>
    <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>

スキャナーを設定する

Bean タグを使用し、クラスは MapperScannerConfigurer を使用し、property タグを使用して dao インターフェースのすべての実装をスキャンし、それを IOC コンテナに追加します (property タグの name 属性値はbasePackage、value 属性値はdao パッケージの名前)

<!--    配置扫描器-->
<bean id="scannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.shenshang.crud.dao"></property>
</bean>

トランザクションマネージャーの構成

Bean タグを使用し、クラスは DataSourceTransactionManager の完全なクラス名を使用し、property タグを使用してデータ ソースを制御します (property タグの name 属性の値は dateSource で、ref 属性の値はデータソース)。

<!--    配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="pooledDataSource"></property>
</bean>

注釈ベースのトランザクションを有効にする

<!--    开启基于注解的事务-->
    <aop:config>
        <aop:pointcut id="txPoint" expression="execution(* com.shenshang.crud.service..*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor>
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
<!--            所有方法都是事务方法-->
            <tx:method name="*"/>
<!--            以get开头的所有方法-->
            <tx:method name="get*" read-only="true"></tx:method>
        </tx:attributes>
    </tx:advice>
</beans>

アノテーションベースのトランザクションを開始するには、トランザクションの XML 構成フォームを使用します (必須で、主に構成タイプを使用します)。aop:config タグを使用する必要があります。このタグの aop:pointcut タグの式属性を使用して、ポイントカット式を記述し、使用します。 aop:advisor タグは、トランザクションの拡張機能を設定します。 aop:advisor タグの属性 advice-ref は、トランザクションに切り込む方法を示します。 値は、 tx:advice タグの id 属性値に対応します。 aop:advisor タグの属性 poincut-ref は、どのメソッドをカットインするかを示します。この値は、aop:pointcut タグの id 値に対応します。tx:attributes タグは、tx:advice タグ内でメソッドを設定するために使用できます。tx:method タグの name 属性は、どのメソッドがトランザクション メソッドであるかを示すために使用できます。このメソッドが値を返すことを示すために、属性のみが「true」に設定されます。値はクエリされた値であり、読み取り専用です。

4.MyBatisの設定

対応する構成テンプレートをコピーします

公式ドキュメントの「はじめに」で対応する設定テンプレートを見つけて、次の内容を mybatis-config.xml にコピーします。

<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">

注: 元の Bean タグを削除し、構成タグを記述することも必要です

グローバル設定ファイルの書き込み

公式ドキュメントの設定 XML の設定で mapUnderscoreToCamelCase を見つけて、新しい設定タグを作成します (これは mybatis で最も複雑な設定であり、このタグの設定は基礎となる操作に大きな影響を与える可能性がありますが、ほとんどの場合はデフォルトの設定を使用します)このプロパティを設定する必要はありません。ほとんどの場合、自動マッピング、ハンプ命名マッピング、カスケード ルール、キャッシュを有効にするかどうか、エグゼキュータ タイプなどのいくつかの共通ルールを変更でき、この名前を属性として設定します。設定タグ内の名前の値、およびその value 属性値が true に設定されます。typeAliases タグを使用して Java 型のエイリアスを設定します。この場合、タグ パッケージが使用され、その属性値名が com.shenshang.crud.bean に設定されます。これにより、com.shenshang.crud.bean の下にある型が自動的にスキャンされます。後続の設定ファイル category.xml で resultType を使用する場合、すべての com.shenshang.crud.bean.Category を記述する代わりに、Category を直接使用できます。

<configuration>
<!--    驼峰命名规则-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
<!--    起别名-->
    <typeAliases>
        <package name="com.shenshang.crud.bean"/>
    </typeAliases>
</configuration>

MyBatis リバース エンジニアリングを使用して、対応する Bean とマッパーを生成する
MyBatis Generator: 略して MBG は、MyBatis フレームワーク ユーザー向けに特別にカスタマイズされたコード ジェネレーターであり、テーブルに従って対応するマッピング ファイル、インターフェイス、Bean クラスを迅速に生成できます。基本的な追加、削除、変更、クエリ、および QBC スタイルの条件付きクエリをサポートします。ただし、テーブル接続やストアドプロシージャなどの複雑なSQLの定義は手動で記述する必要があります。Maven 公式 Web サイトで mybatis ジェネレーターを検索し、依存関係を pom.xml にコピーします。

<!--      MyBatis逆向工程-->
<dependency>
     <groupId>org.mybatis.generator</groupId>
     <artifactId>mybatis-generator-core</artifactId>
     <version>1.4.0</version>
 </dependency>

ssm_crud に従業員テーブル tbl_emp と部門テーブル tbl_dept を作成し、2 つのテーブル間に外部キー関係を作成します。mybatis のリバース エンジニアリングの使用方法については、mybatis 公式 Web サイトのクイック スタート ガイドを参照してください (直接参照することもできます) [公式 Web サイトの XML 構成リファレンス] の場合、コードをコピーして、新しく作成したメイン プロジェクトの mbg.xml ファイルに貼り付けます])。mbg.xml ファイルの変更を開始し、デフォルト情報を必要な情報に変更し、mbg.xml の classpathEntry タグを削除し、データベース接続を構成し、javaBean が生成される場所を指定し、SQL マッピング ファイルの場所を指定します。 table の位置は各テーブルの生成方針を指定します (table タグの tableName 属性がテーブル名、domainObjectName が自動生成されるクラス名に対応します)。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

<!--    配置数据库连接-->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm_crud"
                        userId="root"
                        password="szx...2943">
        </jdbcConnection>

        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
<!--指定javaBean生成的位置-->
        <javaModelGenerator targetPackage="com.shenshang.crud.bean" targetProject="path">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

<!--        指定映射文件生成的位置-->
        <sqlMapGenerator targetPackage="mapper"  targetProject="path">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

<!--        指定dao接口生成的位置-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.shenshang.crud.dao"  targetProject="path">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

<!--        table指定每个表的生成策略-->
        <table tableName="tbl_emp" domainObjectName="Employee"></table>
        <table tableName="tbl_dept" domainObjectName="Department"></table>

    </context>
</generatorConfiguration>

注: このコードでは、targetPackage 属性の値は path に置き換えられ、対応するファイル path\textcolor{red}{注: このコードでは、targetPackage 属性の値は次のように置き換えられます。 path であり、対応するファイル パス file path に置き換える必要があります。}:このコードターゲットパッケージ属性p a th置き換えられ対応するファイルパス置き換える必要あります_ _ _ _

MyBatis 公式 Web サイトの「Running MyBatis Generator」で Java プログラムを見つけ、コードを新しく作成した com.shenshang.crud.test パッケージの下の MBGTest.java ファイルにコピーします (コード内で変更が必要な部分は File( "")、ファイル内の値を mbg.xml) に変更する必要があります。

   List<String> warnings = new ArrayList<String>();
   boolean overwrite = true;
   File configFile = new File("generatorConfig.xml");
   ConfigurationParser cp = new ConfigurationParser(warnings);
   Configuration config = cp.parseConfiguration(configFile);
   DefaultShellCallback callback = new DefaultShellCallback(overwrite);
   MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
   myBatisGenerator.generate(null);

注:この時に生成されるBeanクラスにはコメントが多く含まれています コメントを削除する方法:MyBatis公式サイトのXML Configuration内にあるcommentGeneratorタグを見つけて一番下にサンプルがあり、サンプルコードをコピーして変更します。属性値 プロパティタグの名前 mbg.xml の context タグの下に、suppressAllComments を貼り付けます (以前に生成された Bean ファイルを削除することに注意してください)

<commentGenerator>
    <property name="suppressAllComments" value="true" />
</commentGenerator>

注: 属性 targetPackage の値はパッケージ名です。パッケージ名は存在しない場合があります。自動的に作成されます。属性 targetProject の値はプロジェクト ディレクトリ名であり、すでに存在している必要があります。存在しない場合はエラーが報告されます。 , そして targetProject の値が始まります ディレクトリは現在のサブモジュール ディレクトリです。Maven マルチモジュール プロジェクトでは、相対ディレクトリを使用して、同じレベルのサブモジュールに切り替えることができます (例: .../shopping_bean/src/main) /java

5. マッパー ファイルを変更してテストする

お問い合わせの際は所属部署の情報をご持参ください

spring-test をインポートする必要がある単体テストは、pom.xml ファイルによって異なります。

      <!--      Spring的单元测试依赖-->
      <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>5.3.15</version>
          <scope>test</scope>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>5.3.15</version>
          <scope>compile</scope>
      </dependency>

テーブル tbl_emp とテーブル tbl_dept は外部キー d_id で関連付けられているため、従業員情報のクエリには部門情報も含まれることが望ましいため、EmployeeMapper.xml に新しいクエリ文を記述します。その前に、EmployeeMapper.java インターフェース ファイルに 2 つのクエリ ステートメントを追加し、クラス属性部門を追加して、Employee.java エンティティ クラス ファイルにゲッター メソッドとセッター メソッドを生成する必要があります。

/*增添在EmployeeMapper.java接口文件中的查询语句*/
//    查询带有部门信息的员工信息
List<Employee> selectByExampleWithDept(EmployeeExample example);

Employee selectByPrimaryKeyWithDept(Integer empId);

/*增添在Employee.java实体类文件中的语句*/
private Department department;

public Department getDepartment() {
    
    
    return department;
}

public void setDepartment(Department department) {
    
    
    this.department = department;
}

EmployeeMapper.xml ファイルに、新しい選択タグ ステートメントと SQL タグ ステートメントを記述し、部門情報なしで従業員情報をクエリするために生成された選択タグ ステートメント コードから選択タグ ステートメントをコピーし、生成された SQL タグ ステートメントに従って選択ラベルを生成します。ステートメントを使用して新しいステートメントを作成するには、dept_id および dept_name 情報を新しい SQL ラベル ステートメントに含める必要があり、select label ステートメントを作成するときに結合テーブル クエリを使用する必要があります (ステートメントでの左結合の使用に注意してください: left join : 左に置きます。右にあるものをすべて確認します。右に何かがある場合は一致します。そうでない場合は null になります)。戻り値がコレクションであるメソッドの select タグ文で属性 resultMap を使用し、さらに resultMap タグを作成します タグ内で関連タグ (association 属性) を使用する必要があります javaType: 完全な Java クラスname または alias. property: データベース列をマップするエンティティ オブジェクトのプロパティ id. この項目を設定すると、MyBatis のパフォーマンスが効果的に向上します result. property: データベース列をマップするエンティティ クラス オブジェクトの属性 column : データベース列名またはエイリアス)、関連付けタグは deptId クラス属性に対応する id タグを使用する必要があり、クエリに対応する属性 deptName を返すには result タグを使用します。

<!--  查询带有部门信息的员工信息的resultMap-->
  <resultMap id="WithDeptResultMap" type="com.shenshang.crud.bean.Employee">
    <id column="emp_id" jdbcType="INTEGER" property="empId" />
    <result column="emp_name" jdbcType="VARCHAR" property="empName" />
    <result column="gender" jdbcType="CHAR" property="gender" />
    <result column="email" jdbcType="VARCHAR" property="email" />
    <result column="d_id" jdbcType="INTEGER" property="dId" />
    <association property="department" javaType="com.shenshang.crud.bean.Department">
      <id column="dept_id" property="deptId"></id>
      <result column="dept_name" property="deptName"></result>
    </association>
  </resultMap>
<!--  查询带有部门信息的员工信息的查询列表项-->
  <sql id="WithDept_Column_List">
    e.emp_id, e.emp_name, e.gender, e.email, e.d_id, d.dept_id, d.dept_name
  </sql>
<!--  查询带有部门信息的员工信息-->
  <select id="selectByExampleWithDept" parameterType="com.shenshang.crud.bean.EmployeeExample" resultMap="WithDeptResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    from tbl_emp e left join tbl_dept d on e.'d_id' = d.'dept_id'
    <if test="_parameter != null">
      <include refid="WithDept_Column_List" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
  </select>
  <select id="selectByPrimaryKeyWithDept" parameterType="java.lang.Integer" resultMap="WithDeptResultMap">
    select
    <include refid="WithDept_Column_List" />
    from tbl_emp e left join tbl_dept d on e.'d_id' = d.'dept_id'
    where emp_id = #{empId,jdbcType=INTEGER}
  </select>

テストマッパー
Maven 座標公式 Web サイトで Spring テストの依存関係をクエリし、それを pom.xml ファイルにインポートし、com.shenshang.crud.test パッケージに MapperTest.java テスト クラスを作成し、@ContextConfiguration アノテーションを使用して、 Spring 構成ファイルをクラス名の前に置きます。

ContextConfiguration アノテーションについて: @ContextConfiguration(locations = {"classpath※:/※.xml"})。@ContextConfiguration の括弧内の location = {“classpath:/※.xml”} は、クラスパス内のすべての .xml ファイルがインクルードされ、次に作成した XML ファイルがインクルードされ、その後に自動的に生成される Bean がインクルードされることを意味します。この時点で、テスト クラスで @Autowired アノテーションを使用して、以前に自動的にスキャンされたパッケージ内のすべての Bean を取得できます。

クラスパスとクラスパス*の違い:

  • classpath: クラスパス内のファイルのみを検索します。
  • classpath*: クラスパスだけでなく、jar ファイル (クラスパス) 内の検索も含まれます。

テスト クラスで変数 DeptmentMapper を宣言し、この変数の前に @Autowired アノテーションを追加すると、この変数を介して追加、削除、変更、チェックするメソッドを呼び出してテストできます。(テスト可能: insertSelective)

バッチ挿入をテストするには、application.xml でバッチ実行を実行できる sqlSession を構成し、application.xml に Bean タグを作成します。Bean タグ内の属性値クラスは、SqlSessionTemplate の完全なクラス名を使用し、 id は SqlSessionTemplate として指定されます。Bean タグ内でconstructor-arg タグを使用します。constructor-arg タグの属性値の名前は sqlSessionFactory で、ref は以前に指定した「sqlSessionFactory」を使用します。引き続き、constructor-arg タグの作成を続けます。constructor-arg タグの属性値は executorType、値は BATCH です。テストクラスに戻り値が SqlSession となる変数を作成し、変数の前に @Autowired アノテーションを追加してテストします。(UUID を使用して無意味な ID 番号を生成します: UUID.randomUUID().toString().substring(0,5);)。

<!--    批量添加-->
<bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSessionTemplate">
    <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg>
    <constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>

@Autowired メソッドまたはコンストラクターをマークします。コンストラクターに 2 つの入力パラメーター、つまり bean1 と bean2 がある場合、@Autowired はそのタイプに一致する Bean を検索し、それらを CountryService (Bean1 bean1、Bean2 bean2) の入力パラメーターとして使用して作成します。 CountryService Bean。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    
    "classpath:applicationContext.xml"})
public class MapperTest {
    
    

    @Autowired
    DepartmentMapper departmentMapper;

    @Autowired
    EmployeeMapper employeeMapper;

    @Autowired
    SqlSession sqlSession;

    @Test
    public void CRUDTest(){
    
    
//        departmentMapper.insertSelective(new Department(null,"computer"));
//        employeeMapper.insertSelective(new Employee(null,"Jerry","女","[email protected]",1));

        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        for (int i = 0; i < 10; i++) {
    
    
            String uid = UUID.randomUUID().toString().substring(0, 5);
            employeeMapper.insertSelective(new Employee(null,uid+"Mi","男",uid+"@shenshang"+i,1));
        }

        System.out.println("插入成功!");
        System.out.println(departmentMapper);
//        ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
//        DepartmentMapper bean = ioc.getBean(DepartmentMapper.class);
//        System.out.println(bean);
    }
}

6. クエリ機能の実現

  1. Index.jsp ページにアクセスしてください
  2. Index.jsp ページはクエリ従業員リスト リクエストを送信します。
  3. EmployeeController はリクエストを受け入れ、従業員データを見つけます。
  4. list.jsp ページにアクセスして表示します

コードビハインドでページネーションを完了する

Index.jsp で jsp:forward タグを使用し、タグ内のページ属性値は「/emps」で、com.shenshang.crud.controller に EmployeeController.java ファイルを作成します。ページング プラグインを含むコントロール層コードを EmployeeController.java ファイルに記述します (getEmps メソッドはページ データ表示を返し、getPageInfoWithJson メソッドは Json データの形式でページを返します)。

@Controller
public class EmployeeController {
    
    

    @Autowired
    EmployeeService employeeService;

//    @ResponseBody
//    @RequestMapping("/emps")
    public Msg getPageInfoWithJson(@RequestParam(value = "pn",defaultValue = "1") Integer pn){
    
    
        //在查询之前只需要调用,传入页码,以及每页的大小
        PageHelper.startPage(pn,5);
        //startPage后面紧跟的这个查询就是一个分页查询
        List<Employee> emps = employeeService.getAll();
        //使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就行
        //封装了详细的分页信息,包括我们查询到的数据,传入连续显示的页数
        PageInfo page = new PageInfo(emps,5);
        return Msg.success().add("pageInfo",page);
    }

    @RequestMapping("/emps")
    public String getEmps(@RequestParam(value = "pn",defaultValue = "1") Integer pn, Model model){
    
    
        PageHelper.startPage(pn,5);
        List<Employee> emps = employeeService.getAll();
        PageInfo page = new PageInfo(emps,5);
        model.addAttribute("pageInfo",page);
        return "list";
    }
}

注: pn は pageNumber の略語で、現在のページを意味しますが、JSP ページは pn の値を渡しません。このとき、defaultValue 値を使用して pn にデフォルト値を割り当てることができます。Pag​​eHelper プラグを使用する前に-in では、maven 公式 Web サイトで pageHelper を検索し、pom.xml ファイルに pageHelper 関連の依存関係を導入する必要があります。そして、mybatis にグローバル設定を導入します。

<!--      pageHelper分页插件-->
      <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
      <dependency>
          <groupId>com.github.pagehelper</groupId>
          <artifactId>pagehelper</artifactId>
          <version>5.2.0</version>
      </dependency>
<plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

com.shenshang.crud.service に EmployeeService.java ファイルを作成し、ビジネス ロジック層のコードを記述します。

@Service
public class EmployeeService {
    
    

    @Autowired
    EmployeeMapper employeeMapper;

//    查询所有员工
    public List<Employee> getAll(){
    
    
        return employeeMapper.selectByExampleWithDept(null);
    }
}

注: jsp:forward アクションは、リクエストを別の JSP、サーブレット、または静的リソース ファイルに転送します。リクエストのリダイレクト先のリソースは、リクエストの送信元の JSP と同じコンテキスト、つまり同じ Web アプリケーションまたは同じ Web サイトに存在する必要があります。

<%--    分页--%>
<div class="row">
    <%--        分页条文字信息--%>
    <div class="col-md-6">
        当前显示页数:${pageInfo.pageNum}页,总共${pageInfo.pages}页,总共${pageInfo.total}条记录
    </div>
    <%--        分页条列表项信息--%>
    <div class="col-md-6">
        <nav aria-label="Page navigation">
            <ul class="pagination">
                <li><a href="${APP_PATH}?pn=1">首页</a></li>
                <c:if test="${pageInfo.pageNum!=1}">
                    <li>
                        <a href="${APP_PATH}?pn=${pageInfo.pageNum-1}" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>
                </c:if>
                <c:if test="${pageInfo.pageNum==1}">
                    <li class="disabled">
                        <a href="#" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>
                </c:if>
                <c:forEach items="${pageInfo.navigatepageNums}" var="page_num">
                    <c:if test="${page_num==pageInfo.pageNum}">
                        <li class="active"><a href="${APP_PATH}?pn=${page_num}">${page_num}</a></li>
                    </c:if>
                    <c:if test="${page_num!=pageInfo.pageNum}">
                        <li><a href="${APP_PATH}?pn=${page_num}">${page_num}</a></li>
                    </c:if>
                </c:forEach>
                <c:if test="${pageInfo.pageNum==pageInfo.pages}">
                    <li class="disabled">
                        <a href="#" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                </c:if>
                <c:if test="${pageInfo.pageNum!=pageInfo.pages}">
                    <li>
                        <a href="${APP_PATH}?pn=${pageInfo.pageNum+1}" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                </c:if>
                <li><a href="${APP_PATH}?pn=${pageInfo.pages}">末页</a></li>
            </ul>
        </nav>
    </div>
</div>

Query-ajax: ページ化された JSON データを返す

  1. Index.jsp ページは、従業員のページ データをクエリするための Ajax リクエストを直接送信します。
  2. サーバーは検出されたデータを json 文字列の形式でブラウザに返します。
  3. ブラウザーは json 文字列を受け取り、js を使用して json を解析し、js を使用して dom の追加、削除、および変更を通じてページを変更できます。
  4. jsonを返します。クライアントの独立性を実現します。

データを json 形式で返す前に、jackson の依存関係を pom.xml ファイルにインポートする必要があります。

<!--      支持返回json字符串-->
      <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
      <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.13.1</version>
      </dependency>

PageInfo タイプ (@ResponseBody アノテーションが付けられている) を返す新しいメソッドを EmployeeController.java に作成します。@ResponseBody アノテーションが適切に機能するためには、jackson パッケージの依存関係をインポートする必要があります。Msg.java の一般的な戻りクラスを Bean パッケージの下に作成します。

注: @ResponseBody 関数: このアノテーションは、Controller メソッドによって返されたオブジェクトを、適切な HttpMessageConverter を通じて指定された形式に変換し、それを Response オブジェクトの本文データ領域に書き込むために使用されます。使用する場合: 返されるデータが HTML タグを含むページではなく、他の形式 (json、xml など) のデータである場合に使用します。

//通用的返回类
public class Msg {
    
    
//    状态码 100-成功  200-失败
    public int code;

//    提示信息
    public String msg;

//    用户要返回浏览器的数据
    public Map<String,Object> extend = new HashMap<String, Object>();

//    返回处理成功的Msg
    public static Msg success(){
    
    
        Msg result = new Msg(100,"处理成功");
        return result;
    }

//    返回处理失败的Msg
    public static Msg fail(){
    
    
        Msg result = new Msg(200,"处理失败");
        return result;
    }

//    添加信息到map集合中
    public Msg add(String key , Object value){
    
    
        this.getExtend().put(key, value);
        return this;
    }

    public Msg(int code, String msg) {
    
    
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
    
    
        return code;
    }

    public void setCode(int code) {
    
    
        this.code = code;
    }

    public String getMsg() {
    
    
        return msg;
    }

    public void setMsg(String msg) {
    
    
        this.msg = msg;
    }

    public Map<String, Object> getExtend() {
    
    
        return extend;
    }

    public void setExtend(Map<String, Object> extend) {
    
    
        this.extend = extend;
    }
}

上記の一般的な戻り値を記述した後、EmployController クラスの getEmps メソッドをコメントアウトし、getPageInfoWithJson メソッドを使用すると、/emps ページにアクセスしたときに json データの戻り値が取得されます。このときの考え方としては、インデックスページはjsを使ってajaxリクエストを送り、jsはページの従業員データを取得したい、取得した従業員データをjsが解析してページに表示する、ということになります。

新しいindex.jspファイルを作成し、list.jspファイル内のコードを新しく作成したindex.jspファイルにコピーし、ajaxテクノロジを使用してリスト情報とページネーション情報をクエリおよび表示できるように変換します。関連する JS コードを記述して、JSON データを取得し、従業員リスト データを解析し、ページング バーのテキスト情報を解析し、ページング バーの情報を解析して JSP ページに表示します。[最初にリスト、ページングバー、ページング情報を表示し、その後詳細の js コードを実装します]:

<script type="text/javascript">
    $(function () {
    
    
        to_page(1);
    });
    function to_page(pn) {
    
    
        // 页面加载完DOM以后发送ajax请求
        $.ajax({
    
    
            url:"${APP_PATH}/emps",
            data:"pn="+pn,
            type:"get",
            success:function (result) {
    
    
                // console.log(result);
                // 解析并展示员工数据
                build_emps_table(result);
                // 解析展示分页文字信息
                build_page_info(result);
                // 解析展示分页条信息
                build_nav_info(result);
            }
        });
    }
    // 解析展示员工数据
    function build_emps_table(result) {
    
    
        // 清空table表格
        $("#emps_table tbody").empty();
        let emps = result.extend.pageInfo.list;
        $.each(emps,function (index,item) {
    
    
            let empIdTd = $("<td></td>").append(item.empId);
            let empNameTd = $("<td></td>").append(item.empName);
            let gendTd = $("<td></td>").append(item.gender);
            let emailTd = $("<td></td>").append(item.email);
            let deptNameTd = $("<td></td>").append(item.department.deptName);
            let editBtn = $("<button></button>").addClass("btn btn-success btn-sm glyphicon glyphicon-pencil").append("编辑");
            let deltBtn = $("<button></button>").addClass("btn btn-warning btn-sm glyphicon glyphicon-trash").append("删除");
            let btnTd = $("<td></td>").append(editBtn).append(" ").append(deltBtn);
            $("<tr></tr>")
                .append(empIdTd)
                .append(empNameTd)
                .append(gendTd)
                .append(emailTd)
                .append(deptNameTd)
                .append(btnTd)
                .appendTo("#emps_table tbody");
        })
    }
    // 解析展示分页文字信息
    function build_page_info(result) {
    
    
        $("#page_info_area").empty();
        // 当前显示页数:页,总共页,总共条记录
        $("#page_info_area").append("当前显示页数:"+result.extend.pageInfo.pageNum+"页,总共"+result.extend.pageInfo.pages+"页,总共"+result.extend.pageInfo.total+"条记录")
    }

    // 解析展示分页条信息
    function build_nav_info(result) {
    
    
        $("#page_nav_area").empty();
        let firstPage = $("<li></li>").append($("<a></a>").append("首页").attr("href","#"));
        let previousPage = $("<li></li>").append($("<a></a>").append("&laquo;").attr("href","#"));
        // 如果当前页是第一页
        if (result.extend.pageInfo.pageNum == 1){
    
    
            firstPage.addClass("disabled");
            previousPage.addClass("disabled");
        }
        else {
    
    
            firstPage.click(function () {
    
    
                to_page(1);
            })
            previousPage.click(function () {
    
    
                to_page(result.extend.pageInfo.pageNum - 1);
            })
        }

        // 使用bootstrap内置类
        let ul = $("<ul></ul>").addClass("pagination");

        let nextPage = $("<li></li>").append($("<a></a>").append("&raquo;").attr("href","#"));
        let lastPage = $("<li></li>").append($("<a></a>").append("末页").attr("href","#"));
        // 如果当前页是末页
        if (result.extend.pageInfo.pageNum == result.extend.pageInfo.pages){
    
    
            nextPage.addClass("disabled");
            lastPage.addClass("disabled");
        }
        else{
    
    
            nextPage.click(function () {
    
    
                to_page(result.extend.pageInfo.pageNum + 1);
            })
            lastPage.click(function () {
    
    
                to_page(result.extend.pageInfo.pages);
            })
        }

        // 向ul列表中加入首页和上一页
        ul.append(firstPage).append(previousPage);
        $.each(result.extend.pageInfo.navigatepageNums,function (index,item) {
    
    
            let numLi = $("<li></li>").append($("<a></a>").append(item).attr("href","#"));
            // 设置当前页分页条高亮显示
            if (result.extend.pageInfo.pageNum == item){
    
    
                numLi.addClass("active");
            }
            // 给分页条每个分页添加点击事件
            numLi.click(function () {
    
    
                to_page(item);
            })
            ul.append(numLi);
        })
        // 向ul列表中加入末页和下一页
        ul.append(nextPage).append(lastPage);

        let navEle = $("<nav></nav>").append(ul);
        navEle.appendTo("#page_nav_area");
    }
</script>

注: $(function(){}) 関数は、DOM がロードされた後に実行されます。DOM は HTML ページのタグ ツリーです。DOM がロードされた後は、ページ上のすべての HTML タグ (画像を含む) がロードされたことを意味します。つまり、ブラウザーが応答し、ロードされ、すべてが表示されました。

7. 新機能の実現

従業員用に新しいモーダル ボックスを作成する

  1. Index.jsp ページの「追加」をクリックします。
  2. 新しいダイアログをポップアップする
  3. データベースにアクセスして、ダイアログ ボックスに表示される部門リストを照会します。
  4. ユーザーが入力したフォームデータを検証する
  5. ユーザーがデータを入力して保存する

ブートストラップ スタイル ライブラリの js プラグインを使用して新しいモーダル ボックスを作成し、クリック イベントをindex.jsp ページの新しいボタンにバインドして、新しいボタンをクリックするとモーダル ボックスが開くようにします (js コードが必要です)。具体的な方法(ブートストラップスタイルライブラリのjsプラグインにおけるモーダルボックスの使い方を参照); ブートストラップスタイルライブラリを使用して、モーダルボックスにフォームと送信ボタンを記述します。

<%--    按钮--%>
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary" id="emp_add_modal_btn">增加</button>
            <button class="btn btn-danger">删除</button>
        </div>
    </div>

<%--    模态框--%>
    <!-- Modal -->
    <div class="modal fade" id="emps_add_input" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                    <h4 class="modal-title" id="myModalLabel">新增员工</h4>
                </div>
                <div class="modal-body">
                    <form class="form-horizontal">
                        <div class="form-group">
                            <label class="col-sm-2 control-label">empName:</label>
                            <div class="col-sm-10">
                                <input type="text" name="empName" class="form-control" id="empName_add_input" placeholder="empName">
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="col-sm-2 control-label">email:</label>
                            <div class="col-sm-10">
                                <input type="email" name="email" class="form-control" id="email_add_input" placeholder="email">
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="col-sm-2 control-label">gender:</label>
                            <div class="col-sm-10">
                                <label class="radio-inline">
                                    <input type="radio" name="gender" id="gender1_add_input" checked="checked" value="M"> 男
                                </label>
                                <label class="radio-inline">
                                    <input type="radio" name="gender" id="gender2_add_input" value="F"> 女
                                </label>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="col-sm-2 control-label">deptName:</label>
                            <div class="col-sm-10">
                                <select class="form-control">

                                </select>
                            </div>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                    <button type="button" class="btn btn-primary">保存</button>
                </div>
            </div>
        </div>
    </div>
<script>
        // 点击新增按钮弹出模态框
    $("#emp_add_modal_btn").click(function () {
        $("#emps_add_input").modal({
            backdrop:"static"
        })
    });
</script>

Ajaxはドロップダウンボックスの部門情報を表示します

モーダル ボックスをポップアップする前に、部門情報を検索してドロップダウン リストに表示するために ajax リクエストを送信する必要があります。com.shenshang.crud.controller パッケージ内にDepartmentController.java ファイルを作成し、サービス パッケージ内にDepartmentService ビジネス ロジック クラスを作成し、ビジネス ロジック クラス内にDepartmentMapper エンティティ クラス属性を作成し、dao レイヤー関数を呼び出して、リストをクエリします。部門情報のモーダルボックスのドロップダウンリストに表示されます。

記述されたDepartmentControllerコントロールクラスのコードは次のとおりです。

@Controller
public class DepartmentController {
    
    
    @Autowired
    private DepartmentService departmentService;

    @ResponseBody
    @RequestMapping("/depts")
    public Msg getDeptWithJson(){
    
    
        List<Department> list = departmentService.getDepts();
        return Msg.success().add("depts",list);
    }
}

DepartmentService ビジネス クラス コードは次のように記述されます。

@Service
public class DepartmentService {
    
    
    @Autowired
    private DepartmentMapper departmentMapper;

    public List<Department> getDepts() {
    
    
        List<Department> list = departmentMapper.selectByExample(null);
        return list;
    }
}

jsp ページは ajax を使用してデータベース データを取得し、サーバーと対話します。

    // 点击新增按钮弹出模态框
    $("#emp_add_modal_btn").click(function () {
    
    
        // 发送ajax请求
        $.ajax({
    
    
            url: "${APP_PATH}/depts",
            type: "GET",
            success:function (result) {
    
    
                // console.log(result);
                // 显示部门信息在下拉列表中
                // 每次添加数据库内容想下拉列表时都情况下拉列表中的内容
                $("#dept_select_input").empty();
                $.each(result.extend.depts,function (index,item) {
    
    
                    let optionEle = $("<option></option>").append(item.deptName).attr("value",item.deptId);
                    optionEle.appendTo("#dept_select_input");
                })
            }
        })

        // 弹出模态框
        $("#emps_add_input").modal({
    
    
            backdrop:"static"
        })
    });

保存ボタンの実装

URI:

  • /emp/{id} GET クエリ従業員
  • /emp POST 従業員を保存
  • /emp/{id} PUT 従業員を変更する
  • /emp/{id} DELETE 従業員を削除する

EmployeeController コントロール クラスと EmployeeService ビジネス クラスに saveEmp メソッドを記述し、メソッド本体でサービス エンティティ クラスを使用して EmployeeService クラスの saveEmp メソッドを呼び出し、Msg エンティティ クラスを返します。

EmployeeController コントロール クラスの新しいメソッド:

    @ResponseBody
    @RequestMapping(value = "/emp",method = RequestMethod.POST)
    public Msg saveEmp(Employee employee){
    
    
        employeeService.saveEmp(employee);
        return Msg.success();
    }

EmployeeService ビジネス クラスの新しいメソッド:

//    保存新增员工数据
    public void saveEmp(Employee employee) {
    
    
        employeeMapper.insertSelective(employee);
    }

インデックス ページに js コードを記述し、保存ボタンをクリックした後に ajax を使用してデータをデータベースに転送し、モーダル ボックスを終了して、リストの最後のページを直接表示します。

    // 点击保存按钮保存新增员工数据
    $("#save_emp_btn").click(function () {
    
    
        // 模态框中填写的员工数据提交给服务器保存
        // 发送ajax请求保存员工
        $.ajax({
    
    
            url: "${APP_PATH}/emp",
            type: "POST",
            data: $("#emps_add_input form").serialize(),
            success: function () {
    
    
                $("#emps_add_input").modal('hide');
                to_page(pagesTotal);
            }
        })
    })

注: jquery の Serialize() メソッド: シリアル テーブル テーブルの内容は文字列であり、Ajax リクエストに使用されます。

jQueryフロントエンド検証の実装

新しい関数 validate_add_form() を作成します。保存ボタンをクリックして Ajax リクエストを送信する前に、 validate_add_form() 関数を呼び出してユーザーが入力したフォーム データを検証し、関数本体内で正規表現を使用してデータの有効性を判断します。入力:

    // 校验用户输入的表单数据
    function validate_add_form(){
    
    
        let empName = $("#empName_add_input").val();
        let regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
        if (!regName.test(empName)){
    
    
            alert("用户名为6-16位英文(包含字符)或2-5个汉字");
            return false;
        }
        let email = $("#email_add_input").val();
        let regEmail = /^([a-z0-9\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
        if (!regEmail.test(email)){
    
    
            alert("邮箱输入格式有误!");
            return false;
        }
        return true;
    }

ブートストラップを使用して検証プロンプト情報を美しくする

ブートストラップ スタイル ライブラリの検証スタイルを使用して、フォーム データの検証を美しくすることができます。フォーム検証関数 show_validate_msg() を作成し、最初に関数本体で RemoveClass() メソッドを使用して指定されたラベル スタイルをクリアしてから、入力パラメータ 判定を行う 検証情報が正しい場合は、対応するラベルのスタイルを設定 検証情報が間違っている場合は、対応するラベルのスタイルを設定してプロンプトメッセージを表示する jsコードは次のとおりです。

    // 校验用户输入的表单数据
    function validate_add_form(){
    
    
        let empName = $("#empName_add_input").val();
        let regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
        if (!regName.test(empName)){
    
    
            // alert("用户名为6-16位英文(包含字符)或2-5个汉字");
            show_validate_msg("#empName_add_input","error","用户名为6-16位英文(包含字符)或2-5个汉字");
            return false;
        }
        show_validate_msg("#empName_add_input","success","格式正确");
        let email = $("#email_add_input").val();
        let regEmail = /^([a-z0-9\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
        if (!regEmail.test(email)){
    
    
            // alert("邮箱输入格式有误!");
            show_validate_msg("#email_add_input","error","邮箱输入格式有误!");
            return false;
        }
        show_validate_msg("#email_add_input","success","格式正确");
        return true;
    }
    // 校验表单数据函数
    function show_validate_msg(ele,status,msg){
    
    
        $(ele).parent().removeClass("has-success has-error");
        $(ele).next("span").text("");
        if (status == "success"){
    
    
            $(ele).parent().addClass("has-success");
            $(ele).next("span").text(msg);
        }else if (status == "error"){
    
    
            $(ele).parent().addClass("has-error");
            $(ele).next("span").text(msg);
        }
    }

Ajax はユーザー名が重複していないかどうかをチェックします

ユーザー名が重複していてもデータベースにユーザーを追加できる場合は、ユーザー名に応じてユーザーを問い合わせる機能に影響があり、実際の開発・立ち上げに適合しないため確認が必要です。新しいユーザーを追加するときにフォーム内のユーザー名を繰り返すかどうか。従業員入力ボックスのバインディング変更イベントを追加し、EmployeeService クラスに新しいメソッド checkUser を作成し、EmployeeController コントロール クラスに checkUser メソッドを記述し、employeeService エンティティ クラスを使用してメソッド本体で checkUser メソッドを呼び出し、ユーザー名は checkUser メソッドの戻り値に基づいています。Available は、汎用情報クラスの成功または失敗のメッセージを返します。checkUser メソッドでは、EmployeeExample のエンティティ クラスの例を作成する必要があります。Criteria エンティティ クラスは、エンティティ クラスを通じて createCriteria メソッドを呼び出すことによって作成されます。動的 SQL ステートメントは、Criteria エンティティ クラスを通じて andEmpNameEqualTo メソッドを呼び出すことによってアセンブルされます。最後に、countByExample メソッドが、employeeMapper エンティティ クラスを通じて呼び出され、ブール型メソッドの戻り値を返します。

EmployeeController コントロール クラスに checkUser メソッドを記述します。

    @ResponseBody
    @RequestMapping("/checkuser")
    public Msg checkUser(@RequestParam(value = "empName") String empName){
    
    
        if (employeeService.checkUser(empName)){
    
    
            return Msg.success();
        }
        return Msg.fail();
    }

EmployeeService ビジネス クラスに checkUser メソッドを作成します。

//    检验用户名是否有重复,是否可用
    public boolean checkUser(String empName) {
    
    
        EmployeeExample example = new EmployeeExample();
        EmployeeExample.Criteria criteria = example.createCriteria();
        criteria.andEmpNameEqualTo(empName);
        long count = employeeMapper.countByExample(example);
        return count == 0 ;
    }

ユーザー名が重複していて使用できないかどうかを確認するための js コードをindex.jsp に記述します。

 // 检验用户名是否重复而不可用
    $("#empName_add_input").change(function () {
    
    
        let empName = this.value;
        $.ajax({
    
    
            url:"${APP_PATH}/checkuser",
            type: "POST",
            data:"empName="+encodeURI(empName),
            success:function (result) {
    
    
                if (result.code == 100){
    
    
                    show_validate_msg("#empName_add_input","success","用户名可用");
                    // 给保存按钮增添属性,方便校验用户输入数据
                    $("#save_emp_btn").attr("ajax-va","success");
                }else {
    
    
                    show_validate_msg("#empName_add_input","error","用户名重复不可用!");
                    $("#save_emp_btn").attr("ajax-va","error");
                }
            }
        })
    })

また、保存ボタン メソッドに、ユーザーをチェックするために繰り返されるコード ブロックを追加することにも注意してください。

// 点击保存按钮保存新增员工数据
    $("#save_emp_btn").click(function () {
    
    
        // 模态框中填写的员工数据提交给服务器保存
        if (!validate_add_form()){
    
    
            return false;
        }
        // 校验用户名是否重复
        if ($(this).attr("ajax-va") == "error"){
    
    
            //清除之前校验数据是否合法时添加的样式
            $("#empName_add_input").parent().removeClass("has-error has-success");
            $("#empName_add_input").next("span").text("");
            show_validate_msg("#empName_add_input","error","用户名重复不可用!");
            return false;
        }
        // 发送ajax请求保存员工
        $.ajax({
    
    
            url: "${APP_PATH}/emp",
            type: "POST",
            data: $("#emps_add_input form").serialize(),
            success: function () {
    
    
                $("#emps_add_input").modal('hide');
                to_page(pagesTotal + 1);
            }
        })
    })

注: 新しく追加された従業員データを保存するための保存ボタンのコード実装では、従業員を保存するための Ajax リクエストが正常に送信された後、to_page 関数が呼び出され、パラメーター PagesTotal がすぐに渡されます。ページ (前のページからページの最後までのみ表示できる) であるため、渡されるパラメーターの値が合計ページ数以上になるように、pageTotal+1 を設定します。{実際には、図の便宜上、非常に大きな数値 (例: 99999) を直接渡すと、ページの最後に直接移動できます}

Ajax 検証ユーザー名の詳細処理

現時点ではコードにはまだ不完全な点があり、たとえば、ユーザーが 222 と入力すると、そのユーザー名はデータベースに存在しないため、ユーザー名は正当ですが、222 はユーザー名の命名仕様を満たしていません。名前が標準化されていないことをユーザーに確認するプロンプト メッセージ ユーザーが保存ボタンをクリックした後にのみ表示されます。たとえば、ユーザーが保存をクリックした後、モーダル ボックスが閉じられ、モーダル ボックスが再度開かれると、スタイルが変更されます。入力ボックスがクリアされていないため、次の 2 つの問題に対してコードを改善してください。

ユーザー検証はバックエンドでも実行されます。EmployController コントロール クラスの checkUser メソッドを改善し、ユーザー名が無効な場合は最初に Msg のエラー メッセージを返し、フロントエンドのindex.jsp でエラー メッセージを受け取ります。

    @ResponseBody
    @RequestMapping("/checkuser")
    public Msg checkUser(@RequestParam(value = "empName") String empName){
    
    
//        判断用户名是否合法
        String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})";
        if (!empName.matches(regx)){
    
    
            return Msg.fail().add("va_msg","用户名必须是6-16位的英文或者2-5位中文!");
        }
//        判断用户名是否重复,是否可用
        if (employeeService.checkUser(empName)){
    
    
            return Msg.success();
        }
        return Msg.fail().add("va_msg","用户名不可用!");
    }

フロントエンドは以下を受け取ります。

// 检验用户名是否重复而不可用
$("#empName_add_input").change(function () {
    
    
    let empName = this.value;
    $.ajax({
    
    
        url:"${APP_PATH}/checkuser",
        type: "POST",
        data:"empName="+empName,
        success:function (result) {
    
    
            if (result.code == 100){
    
    
                show_validate_msg("#empName_add_input","success","用户名可用");
                // 给保存按钮增添属性,方便校验用户输入数据
                $("#save_emp_btn").attr("ajax-va","success");
            }else {
    
    
                show_validate_msg("#empName_add_input","error",result.extend.va_msg);
                $("#save_emp_btn").attr("ajax-va","error");
            }
        }
    })
})

フォーム データとフォーム スタイルをクリアするには、index.jsp 内にreset_form メソッドを作成します。

    // 清楚表单内容
    function reset_form(ele){
    
    
        // 清楚表单输入框的内容
        $(ele)[0].reset();
        $(ele).find("*").removeClass("has-error has-success");
        $(ele).find(".help-block").text("");
    }

注意: jqueryにはreset()メソッドはありません。フォームはDOMでresetメソッドを呼び出すことによってリセットされます。

JSR303チェックサムデータ

ユーザーが F12 を使用してフロントエンド コードを変更して、フロントエンド検証を超えた悪意のあるデータの保存を行うことを防ぐには、保護層である JSR303 バックエンド検証を追加する必要があります。

Hibernate-Vaildator 依存関係を Maven の pom.xml にインポートします。

<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>7.0.4.Final</version>
</dependency>

Employ クラスの empName 属性と email 属性の前に @Pattern 属性を追加し、属性内に正規表現を追加して、エラー戻り情報を決定します。Java ファイル内の \ はエスケープ文字であるため、正規表現内の \ は Java ファイル内の \\ に変更できることに注意してください。EmployController コントロール クラスの saveEmp メソッドのパラメーター リストに @Valid アノテーションを追加し、BindingResult 型のパラメーター結果をパラメーター リストに追加し、結果パラメーターの hasErrors() メソッドを呼び出して、検証が適切であるかどうかを確認します。パラメータの getFieldErrors メソッドは、検証に失敗した一連のエラー メッセージを取得し、取得した一連のエラー メッセージを走査し、(getFileld メソッドを使用して取得した) 各エラー メッセージのフィールド名と情報を入力します。メソッドと getDefaultMessage メソッドをそれぞれ) マップ コレクション内のマップ セットのキーと値として使用します。最後に、Msg 情報に地図を組み込みます。

@RequestMapping(value="/emp",method=RequestMethod.POST)
@ResponseBody
public Msg saveEmp(@Valid Employee employee,BindingResult result){
    
    
    if(result.hasErrors()){
    
    
        //校验失败,应该返回失败,在模态框中显示校验失败的错误信息
        Map<String, Object> map = new HashMap<>();
        List<FieldError> errors = result.getFieldErrors();
        for (FieldError fieldError : errors) {
    
    
            System.out.println("错误的字段名:"+fieldError.getField());
            System.out.println("错误信息:"+fieldError.getDefaultMessage());
            map.put(fieldError.getField(), fieldError.getDefaultMessage());
        }
        return Msg.fail().add("errorFields", map);
    }else{
    
    
        employeeService.saveEmp(employee);
        return Msg.success();
    }

}

フロントエンドの保存ボタンをクリックした後、表示用のバックエンド データを受信するための js コードを記述します。

// 点击保存按钮保存新增员工数据
$("#save_emp_btn").click(function () {
    
    
    // 模态框中填写的员工数据提交给服务器保存
    if (!validate_add_form()){
    
    
        return false;
    }
    // 校验用户名是否重复
    if ($(this).attr("ajax-va") == "error"){
    
    
        $("#empName_add_input").parent().removeClass("has-error has-success");
        $("#empName_add_input").next("span").text("");
        show_validate_msg("#empName_add_input","error","用户名重复不可用!");
        return false;
    }
    // 发送ajax请求保存员工
    $.ajax({
    
    
        url: "${APP_PATH}/emp",
        type: "POST",
        data: $("#emps_add_input form").serialize(),
        success: function (result) {
    
    
            // alert(result.msg);
            // 信息校验成功
            $("#emps_add_input").modal('hide');
            to_page(pagesTotal + 1);
        }
    })

8. 関数実現の変更

  1. 「編集」をクリックします
  2. ユーザーが変更したモーダルボックスがポップアップ表示されます(ユーザー情報が表示されます)
  3. 「更新」をクリックしてユーザーの変更を完了します

従業員変更モーダルを作成する

フロントエンドのindex.jspページに従業員情報を変更するためのモーダルボックスを追加し、モーダルボックスをポップアップするボタンを設定します。

function get_depts(ele){
    
    
    $.ajax({
    
    
        url: "${APP_PATH}/depts",
        type: "GET",
        success:function (result) {
    
    
            // 显示部门信息在下拉列表中
            // 每次添加数据库内容想下拉列表时都情况下拉列表中的内容
            $("#dept_select_input2").empty();
            $.each(result.extend.depts,function (index,item) {
    
    
                let optionEle = $("<option></option>").append(item.deptName).attr("value",item.deptId);
                // console.log(item.deptId);
                optionEle.appendTo(ele);
            })
        }
    })
}

// 员工信息修改的功能实现
$(document).on("click",".edit_btn",function () {
    
    
    // 每次点击打开模态框前都清空模态框的数据
    reset_form("#emps_update_input form");
    // 发送ajax请求
    get_depts("#dept_select_input2");

    // 弹出模态框
    $("#emps_update_input").modal({
    
    
        backdrop:"static"
    })
})

従業員情報をエコーする

データベース内の既存の従業員情報をモーダル ボックスにエコーします。ブートストラップの CSS グローバル スタイルでフォーム内の静的コントロールを表示し、静的コントロールをユーザー名の後の入力ボックスに置き換えます。 EmployeeController クラスに getEmp メソッドを追加し、getEmp メソッドにクエリ ビジネス ロジックを実装して、 EmployeeService ビジネス クラスの getEmp メソッドを使用して、メソッド本体内で selectByPrimaryKey を呼び出し、指定された ID を持つ雇用オブジェクトをクエリします。フロントエンドのindex.jspページにgetEmp関数を作成し、アクセスのためのajaxリクエストを送信し、バックエンドによって取得されたempをフロントエンドページに表示します。

getEmp メソッドが EmployeeController コントロール クラスに追加されます。

@ResponseBody
@RequestMapping(value = "/emp/{id}",method = RequestMethod.GET)
public Msg getEmp(@PathVariable("id") Integer id){
    
    
    Employee employee = employeeService.getEmp(id);
    return Msg.success().add("emp",employee);
}

getEmp メソッドが EmployeeService ビジネス クラスに追加されます。

//    查询用户信息,用于修改业务
public Employee getEmp(Integer id) {
    
    
    return employeeMapper.selectByPrimaryKey(id);
}

フロントエンドの js コードはデータをエコーし​​ます。

function getEmp(id){
    
    
    $.ajax({
    
    
        url:"${APP_PATH}/emp/"+id,
        type:"GET",
        success:function (result) {
    
    
            // console.log(result);
            let empDate = result.extend.emp;
            $("#empName_update_static").text(empDate.empName);
            $("#email_update_input").val(empDate.email);
            $("#emps_update_input input[name=gender]").val([empDate.gender]);
            $("#dept_select_input2").val([empDate.dId]);
        }
    })
}

// 员工信息修改的功能实现
$(document).on("click",".edit_btn",function () {
    
    
    // 每次点击打开模态框前都清空模态框的数据
    reset_form("#emps_update_input form");
    // 发送ajax请求
    get_depts("#dept_select_input2");

    getEmp($(this).attr("edit-id"));

    // 弹出模态框
    $("#emps_update_input").modal({
    
    
        backdrop:"static"
    })
})

注: editBtn を従業員データ リストに追加するときに edit-id 属性を直接追加し、その属性値を従業員 ID として設定することができます。これにより、attr("edit -id") メソッドを使用して従業員 ID を渡すことができます。 *

デザイン編集更新成功ボタン

EmployeeController コントロール クラスに saveEmp メソッドを記述し、employeeService を使用してメソッド本体で updateEmp メソッドを呼び出し、EmployeeService ビジネス クラスに updateEmp メソッドを記述して、メソッド本体に従業員をクエリする dao 操作を実装します。フロントエンドページに更新ボタンをクリックしてemp_update_btnを保存するjsコードを記述し、メソッド本体でメールボックス情報を確認した後、従業員データの保存と更新を行うajaxリクエストを送信します。

EmployeeController コントロール クラスに saveEmp メソッドを記述します。

@ResponseBody
@RequestMapping(value = "/emp/{empId}",method = RequestMethod.PUT)
public Msg saveEmp(Employee employee){
    
    
    employeeService.updateEmp(employee);
    return Msg.success();
}

EmployeeService ビジネス クラスに updateEmp メソッドを作成します。

//    修改用户信息,并相应保存
public void updateEmp(Employee employee) {
    
    
    employeeMapper.updateByPrimaryKeySelective(employee);
}

フロントエンドはページを表示し、従業員データを保存および更新するための ajax リクエストを送信します。

$("#save_emp_btn2").click(function () {
    
    
    let email = $("#email_update_input").val();
    let regEmail = /^([a-z0-9\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
    if (!regEmail.test(email)){
    
    
        // alert("邮箱输入格式有误!");
        show_validate_msg("#email_update_input","error","邮箱输入格式有误!");
        return false;
    }else {
    
    
        show_validate_msg("#email_update_input","success","格式正确");
    }
    //发送ajax请求保存修改员工信息
    $.ajax({
    
    
        url:"${APP_PATH}/emp/"+ $(this).attr("edit-id"),
        type:"POST",
        data:$("#emps_update_input form").serialize()+"&_method=PUT",
        success:function (result) {
    
    
            alert(result.msg);
        }
    })
})

ajaxがPUTリクエストを直接送信するとエラーが報告される問題を解決する

フロントエンドでajaxリクエストを送信する際、送信リクエストタイプが「PUT」タイプの場合、サーバーはエラーを報告します。エラーの理由: Tomcat はリクエスト本文のデータをマップにカプセル化し、バックエンドはリクエストを通じてマップから値を取得できます。値は request.getParamter() メソッドによって取得されます。ただし、ajax が PUT リクエストを送信するとき、バックグラウンドで request.getParameter() を介してリクエスト本文のデータを取得することはできません。ajax が PUT リクエストを送信するとき、Tomcat はリクエスト本文のデータをマップとしてカプセル化せず、ajax のみをカプセル化します。 sends リクエスト本文は、POST リクエストが行われた場合にのみマップとしてカプセル化されます。

解決策は、web.xml ファイルで HttpPutFormContentFilter インターセプターを構成することです。この関数は、リクエスト本文のデータを解析してマップにパッケージ化し、リクエストは再パッケージ化され、request.getParameter() が書き換えられます。それ自体からパッケージ化されています。 マップからデータを取得します。

web.xml ファイルで HttpPutFormContentFilter インターセプターを構成します。

<filter>
    <filter-name>HttpPutFormContentFilter</filter-name>
    <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HttpPutFormContentFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

EmployeeController コントロール クラスの saveEmp メソッドを変更します。

    @ResponseBody
    @RequestMapping(value = "/emp/{empId}",method = RequestMethod.PUT)
    public Msg saveEmp(Employee employee,HttpServletRequest request){
    
    
        System.out.println("请求体中的值:"+request.getParameter("gender"));
        System.out.println("将要更新的员工数据:"+employee.toString());
        employeeService.updateEmp(employee);
        return Msg.success();
    }

9. 削除機能の実現

個々の従業員の削除

EmployeeController コントロール クラスで deleteEmpById メソッドを作成し、employService エンティティ クラスを使用してメソッド本体で deleteEmp メソッドを呼び出し、employeeMapper を使用して EmployeeService ビジネス クラスの deleteEmp メソッドの deleteByPrimaryKey メソッドを呼び出して、指定された従業員を削除します。フロントエンド ページの削除ボタンをクリックして ajax リクエストを送信し、成功すると現在のページにジャンプします。

EmployeeController コントロール クラスに deleteEmpById メソッドを記述します。

@ResponseBody
@RequestMapping(value = "emp/{id}",method = RequestMethod.DELETE)
public Msg deleteEmpById(@PathVariable("id") Integer id){
    
    
    employeeService.deleteEmp(id);
    return Msg.success();
}

EmployeeService ビジネス クラスに deleteEmp メソッドを作成します。

//    删除单个员工信息
public void deleteEmp(Integer id) {
    
    
    employeeMapper.deleteByPrimaryKey(id);
}

フロントエンドは、削除ボタンのクリック効果を実現します。

// 删除功能,点击删除按钮保存删除后的员工数据
$(document).on("click",".delete_btn",function () {
    
    
    let empName = $(this).parents("tr").find("td:eq(1)").text();
    let empId = $(this).attr("del-id");
    if (confirm("你要删除【"+empName+"】吗?")){
    
    
        $.ajax({
    
    
            url:"${APP_PATH}/emp/"+ empId,
            type:"DELETE",
            success:function (result) {
    
    
                alert(result.msg);
                to_page(currentPage);
            }
        })
    }
})

注: td:eq(1) は、新しい行の 2 番目のセルを選択することを意味します。

デザインチェックボックス すべて選択 すべてのチェックを外します

テーブルのヘッダーにチェックボックスの 1 つのチェックボックスを追加し、テーブル本体の各行にチェックボックスの 1 つのチェックボックスを追加します。ヘッダーのチェックボックスをクリックすると、以下の各行のチェックボックスがオンになるように、対応する js コードを記述します。

// 点击复选框实现全选全不选功能
$("#check_all").click(function () {
    
    
    $(".check_item").prop("checked",$(this).prop("checked"));
})

// 判断单行的复选框是否都选中,表头复选框要跟着变化
$(document).on("click",".check_item",function () {
    
    
    let flag = $(".check_item:checked").length == $(".check_item").length;
    $("#check_all").prop("checked",flag);
})

注: prop メソッドは dom ネイティブ属性の値を変更して読み取り、attr はカスタム属性の値を取得します。

一括削除機能が完了しました

EmployeeController コントロールクラスの deleteEmpById メソッドを変更し、メソッド本体内に判定本体を追加し、入力された文字列が単一の ID であるか ID コレクション文字列であるかを判定し、ID コレクション文字列で ID コレクション文字列を分割し、それぞれの Put を分割しますID をリスト コレクションに追加し、それを EmployeeService ビジネス クラスに渡し、ビジネス クラスで deleteBatch メソッドを作成し、メソッド本体内に Criteria エンティティ クラスを作成して動的 SQL スプライシングを実装し、employeeMapper エンティティ クラスを通じて deleteByExample を呼び出して削除します。バッチ内の従業員:

EmployeeController コントロール クラスの deleteEmpById メソッドを変換します。

@ResponseBody
@RequestMapping(value = "emp/{ids}",method = RequestMethod.DELETE)
public Msg deleteEmpById(@PathVariable("ids")String ids){
    
    
    if (ids.contains("-")){
    
    
        //            批量删除
        List<Integer> idList = new ArrayList<>();
        String[] ids_string = ids.split("-");
        for (String idItem:
             ids_string) {
    
    
            int id = Integer.parseInt(idItem);
            idList.add(id);
        }
        employeeService.deleteBatch(idList);
    }else{
    
    
        //            单个删除
        int id = Integer.parseInt(ids);
        employeeService.deleteEmp(id);
    }
    return Msg.success();
}

EmployeeService ビジネス クラスに deleteBatch メソッドを作成します。

//    批量删除员工
public void deleteBatch(List<Integer> ids){
    
    
    EmployeeExample example = new EmployeeExample();
    EmployeeExample.Criteria criteria = example.createCriteria();
    criteria.andEmpIdIn(ids);
    employeeMapper.deleteByExample(example);
}

フロントエンドが ajax リクエストを送信する js コードを完成させます。

// 批量删除的功能完成
$("#emp_delete_all_btn").click(function () {
    
    
    let empNames = "";
    let empIds = "";
    $.each($(".check_item:checked"),function () {
    
    
        empNames += $(this).parents("tr").find("td:eq(2)").text()+",";
        empIds += $(this).parents("tr").find("td:eq(1)").text()+"-";
    })
    // 去除empNames中末尾多余的逗号
    empNames = empNames.substring(0,empNames.length-1);
    // 去除empIds中末尾多余的逗号
    empIds = empIds.substring(0,empIds.length-1);
    if (confirm("确认删除【"+empNames+"】吗?")){
    
    
        $.ajax({
    
    
            url:"${APP_PATH}/emp/"+empIds,
            type:"DELETE",
            success:function (result) {
    
    
                $("#check_all").prop("checked",false);
                alert(result.msg);
                to_page(currentPage);
            }
        })
    }
})

要約する

このプロジェクトはこれで完了しました。SSM フレームワークの初心者として、デモの実装ではさまざまな困難に遭遇しました。粘り強く頑張った自分に感謝し、最終的には多くの報酬を得ることができました。今後もずっと注目していきたいと思います。シャンシリコンバレーのレイセオン氏に敬意を表します!

おすすめ

転載: blog.csdn.net/qq_54162207/article/details/124386181