← DoniKit 웹 앱으로

HTML·XML 코드 스니펫 13종

MyBatis 매퍼 XML(동적 SQL·foreach·resultMap)과 HTML 문서 기본형 모음입니다. 매퍼는 태그 구조와 SQL 본문을 함께 볼 수 있게 정리했습니다.

웹 앱에서는 빈칸을 채워 완성된 코드를 바로 복사할 수 있습니다.

매퍼 XML 뼈대

DB 접근 · MyBatis 3

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.app.mapper.UserMapper">

  <select id="findById" parameterType="long" resultType="User">
    SELECT id, name, email
      FROM users
     WHERE id = #{id}
  </select>

</mapper>

💡 namespace는 매퍼 인터페이스의 전체 이름(FQCN)과 정확히 일치해야 메서드와 연결된다. resultType의 짧은 별칭은 mybatis-config의 typeAliases 등록 기준 — 등록 안 했으면 FQCN으로.

#{} vs ${} — 바인딩과 치환

DB 접근 · MyBatis 3

<select id="search" resultType="User">
  SELECT id, name, email
    FROM users
   WHERE name LIKE CONCAT('%', #{keyword}, '%')
   ORDER BY ${sortColumn} ${sortDir}  <!-- 화이트리스트 검증을 거친 값만 -->
</select>

💡 #{}는 PreparedStatement 바인딩(안전), ${}는 문자열 그대로 치환 = SQL 인젝션 통로. 열 이름·정렬 방향처럼 바인딩이 불가능한 자리에만, 반드시 서버에서 허용 목록으로 거른 값을 넣는다.

동적 검색 — where + if

DB 접근 · MyBatis 3

<select id="searchOrders" resultType="Order">
  SELECT id, status, amount, created_at
    FROM orders
  <where>
    <if test="status != null and status != ''">
      AND status = #{status}
    </if>
    <if test="fromDate != null">
      AND created_at &gt;= #{fromDate}
    </if>
  </where>
  ORDER BY id DESC
</select>

💡 <where>는 안에 내용이 있을 때만 WHERE를 붙이고 맨 앞 AND/OR를 지워 준다. XML이라 부등호는 &gt;·&lt;로 쓰거나 <![CDATA[ ]]>로 감싼다. test는 OGNL 표현식.

IN절 — foreach

DB 접근 · MyBatis 3

<select id="findByIds" resultType="User">
  SELECT id, name
    FROM users
   WHERE id IN
  <foreach collection="ids" item="id" open="(" separator="," close=")">
    #{id}
  </foreach>
</select>

💡 파라미터가 이름 없는 List면 collection="list", 배열이면 "array", @Param("ids")를 붙였으면 그 이름. 빈 리스트면 IN ()이 되어 문법 오류 — 호출 전에 비었는지 확인하는 게 안전하다.

부분 수정 — set + if

DB 접근 · MyBatis 3

<update id="updateUser">
  UPDATE users
  <set>
    <if test="name != null">name = #{name},</if>
    <if test="email != null">email = #{email},</if>
    updated_at = now()
  </set>
  WHERE id = #{id}
</update>

💡 <set>은 끝에 남는 쉼표를 지워 준다. 모든 if가 거짓이면 SET절이 통째로 사라져 문법 오류 — 항상 남는 컬럼(updated_at) 하나를 두면 안전.

INSERT + 생성 키 받기

DB 접근 · MyBatis 3

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
  INSERT INTO users (name, email, created_at)
  VALUES (#{name}, #{email}, now())
</insert>

💡 useGeneratedKeys는 MySQL·PostgreSQL(auto_increment/serial)용 — 실행 후 파라미터 객체의 id 필드에 채워진다. 오라클 시퀀스는 <selectKey keyProperty="id" order="BEFORE" resultType="long">SELECT seq_user.NEXTVAL FROM dual</selectKey>로 대신한다.

컬럼↔필드 매핑 — resultMap

DB 접근 · MyBatis 3

<resultMap id="userMap" type="User">
  <id     property="id"        column="user_id"/>
  <result property="userName"  column="user_nm"/>
  <result property="createdAt" column="created_at"/>
</resultMap>

<select id="findAll" resultMap="userMap">
  SELECT user_id, user_nm, created_at FROM users
</select>

💡 스네이크→카멜만 문제라면 resultMap 없이 설정 한 줄(mapUnderscoreToCamelCase=true)로 끝난다. resultMap은 이름 규칙으로 안 풀리는 매핑·조인 결과에 쓴다.

공통 조각 재사용 — sql + include

DB 접근 · MyBatis 3

<sql id="userColumns">
  id, name, email, created_at
</sql>

<select id="findActive" resultType="User">
  SELECT <include refid="userColumns"/>
    FROM users
   WHERE status = 'ACTIVE'
</select>

💡 다른 매퍼 파일의 조각은 refid에 네임스페이스까지 붙여 참조한다(com.example.UserMapper.userColumns). SELECT 목록·조인 조건처럼 반복되는 덩어리에 쓴다.

조건 택일 — choose/when

DB 접근 · MyBatis 3

<select id="searchOne" resultType="User">
  SELECT id, name, email
    FROM users
  <where>
    <choose>
      <when test="email != null">email = #{email}</when>
      <when test="name != null">name = #{name}</when>
      <otherwise>status = 'ACTIVE'</otherwise>
    </choose>
  </where>
</select>

💡 choose는 위에서부터 처음 참인 when 하나만 쓴다 — if 여러 개(모두 적용)와 다른 택일 구조. otherwise는 전부 거짓일 때의 기본 조건.

HTML 문서 뼈대

DOM·이벤트 · HTML5

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>문서 제목</title>
</head>
<body>

</body>
</html>

💡 lang="ko"는 스크린리더·검색엔진의 언어 판정 기준. viewport 메타가 없으면 모바일이 데스크톱 폭으로 축소 렌더링한다.

폼 — label 연결·필수 입력

DOM·이벤트 · HTML5

<form action="/submit" method="post">
  <label for="userName">이름</label>
  <input type="text" id="userName" name="userName" required maxlength="30">

  <label for="userEmail">이메일</label>
  <input type="email" id="userEmail" name="userEmail" required>

  <label for="grade">등급</label>
  <select id="grade" name="grade">
    <option value="normal" selected>일반</option>
    <option value="vip">VIP</option>
  </select>

  <button type="submit">저장</button>
</form>

💡 label의 for와 input의 id가 연결돼야 라벨 클릭으로 포커스가 간다. 서버로 전송되는 이름은 id가 아니라 name. form 안의 button은 기본이 submit — 단순 버튼은 type="button"을 명시.

표 — thead·tbody·병합

DOM·이벤트 · HTML5

<table>
  <thead>
    <tr>
      <th scope="col">이름</th>
      <th scope="col" colspan="2">연락처</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>홍길동</td>
      <td>010-0000-0000</td>
      <td>hong@example.com</td>
    </tr>
  </tbody>
</table>

💡 병합은 열=colspan·행=rowspan. th의 scope는 스크린리더가 머리글-데이터 관계를 읽는 기준. 레이아웃용 표는 금물 — CSS로 한다.

시맨틱 레이아웃

DOM·이벤트 · HTML5

<body>
  <header>
    <nav aria-label="주 메뉴">
      <a href="/">홈</a>
      <a href="/board">게시판</a>
    </nav>
  </header>
  <main>
    <section>
      <h1>페이지 제목</h1>
      <article>본문 단위</article>
    </section>
  </main>
  <footer>© 2026 회사명</footer>
</body>

💡 main은 페이지에 하나만. div 대신 의미 태그(header·nav·main·footer)를 쓰면 접근성·SEO가 따라온다 — 구조가 애매한 곳에만 div.