Spring DAO 디자인 실전
인용 하 다.
서로 다른 데이터 소스 와 방언 을 제공 하여 스마트 페이지 를 실현 합 니 다. Spring 단일 모델 로 인해 Cglib 를 이용 하여 동적 데이터 소스 전환 방안 을 실현 할 수 있 습 니 다. 기본 적 인 것 은 말 하지 않 고 코드 를 직접 볼 수 있 습 니 다.
인용 하 다.
지속 적 인 하이퍼링크, 작업 템 플 릿 가 져 오기, JdbcTemplate, SqlSessionTemplate 등
package com.sunshine.basic.dao;
public interface SuperDao {
/**
*
* @return
*/
T getTemplate();
}
인용 하 다.
조회 + 페이지 조작 인터페이스
package com.sunshine.basic.dao;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.JdbcTemplate;
import com.sunshine.basic.dao.page.PagingParameter;
import com.sunshine.basic.exception.DaoAccessException;
/**
* +
* @author OY
* @since 2016/01/20
* @see V2.0.0
*/
public interface JdbcQueryDao extends SuperDao{
/***
*
* ? , name=?
* @param sql
* @param paras
* @return
* @throws DaoAccessException
*/
Object getField(String sql, Object...paras) throws DaoAccessException;
/**
*
* ?
* @param sql
* @param paras
* @return
* @throws DaoAccessException
*/
Object getField(String sql, List
/* */
package com.sunshine.basic.dao;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.JdbcTemplate;
import com.sunshine.basic.exception.DaoAccessException;
public interface JdbcUpdateDao extends SuperDao{
void update(String sql, Object...paras) throws DaoAccessException;
void update(String sql, List paras) throws DaoAccessException;
void update(String sql, Map paras) throws DaoAccessException;
}
/* */
package com.sunshine.basic.dao;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.JdbcTemplate;
import com.sunshine.basic.exception.DaoAccessException;
public interface JdbcInsertDao extends SuperDao{
void insert(String sql, Object...paras) throws DaoAccessException;
void insert(String sql, List paras) throws DaoAccessException;
void insert(String sql, Map paras) throws DaoAccessException;
}
인용 하 다.
작업 이 실현 되 었 고 업데이트, 삽입 이 아직 실현 되 지 않 았 습 니 다.템 플 릿 가 져 오 는 방법 정의, SQL 해상도 기 는 하위 클래스 에서 이 루어 집 니 다 (디자인 모드 의 템 플 릿 모드)
package com.sunshine.basic.dao;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import com.sunshine.basic.dao.page.DataStore;
import com.sunshine.basic.dao.page.PagingParameter;
import com.sunshine.basic.dao.parser.AbstractParser;
import com.sunshine.basic.dao.parser.Dialect;
import com.sunshine.basic.dao.parser.Parser;
import com.sunshine.basic.exception.DaoAccessException;
/**
*
* @author OY
* @since 2016/01/20
* @see V2.0.0
*/
public abstract class AbstractJdbcCommDao implements JdbcQueryDao, JdbcInsertDao, JdbcUpdateDao{
private Logger log = Logger.getLogger(getClass());
private NamedParameterJdbcTemplate nameJdbTemplate;
private JdbcTemplate jdbcTemplate;
public NamedParameterJdbcTemplate getNamedJdbcTemplate(){
nameJdbTemplate = new NamedParameterJdbcTemplate(
getTemplate());
return nameJdbTemplate;
}
/**
* JdbcTemplate
* @return
* @throws DaoAccessException
*/
public abstract JdbcTemplate getSubJdbcTemplate() throws DaoAccessException ;
/**
* ( )
* @return
* @throws DaoAccessException
*/
public abstract Parser getParser() throws DaoAccessException;
@Override
public final JdbcTemplate getTemplate() {
try {
jdbcTemplate = getSubJdbcTemplate();
if(jdbcTemplate == null) {
log.info("jdbcTemplate is not exits!");
throw new IllegalAccessException("jdbcTemplate is not exits!");
//return SpringApplicationContext.getBean(DEFAULT_JDBC_TEMPLATE, JdbcTemplate.class);
}
} catch (Exception e) {
log.error("jdbcTemplate is not exits!");
e.printStackTrace();
}
return jdbcTemplate;
}
@Override
public Object getField(String sql, Object... paras)
throws DaoAccessException {
log.info("jcbksql-" + sql);
Object result = null;
try{
result = getTemplate().queryForObject(sql, paras, Object.class);
}catch(EmptyResultDataAccessException e){
//
}
return result;
}
@Override
public Object getField(String sql, List paras)
throws DaoAccessException {
log.info("jcbksql-" + sql);
return getField(sql, paras.toArray());
}
@Override
public Object getField(String sql, Map paras)
throws DaoAccessException {
log.info("jcbksql-" + sql);
Object result = null;
try{
result = getNamedJdbcTemplate().queryForObject(sql, paras, Object.class);
}catch(EmptyResultDataAccessException e){
//
}
return result;
}
@Override
public Map getObject(String sql, Object... paras)
throws DaoAccessException {
log.info("jcbksql-" + sql);
Map result = null;
try{
result = getTemplate().queryForMap(sql, paras);
}catch(EmptyResultDataAccessException e){
//
}
return result;
}
@Override
public Map getObject(String sql, List paras)
throws DaoAccessException {
log.info("jcbksql-" + sql);
return getObject(sql, paras.toArray());
}
@Override
public Map getObject(String sql, Map paras)
throws DaoAccessException {
log.info("jcbksql-" + sql);
Map result = null ;
try{
result = getNamedJdbcTemplate().queryForMap(sql, paras);
}catch(EmptyResultDataAccessException e){
//
}
return result;
}
@Override
public T getObject(String sql, Class classz, Object... paras)
throws DaoAccessException {
log.info("jcbksql-" + sql);
T result = null;
try{
result = getTemplate().queryForObject(sql, paras, new BeanPropertyRowMapper(classz));
}catch(EmptyResultDataAccessException e){
//
}
return result;
}
@Override
public T getObject(String sql, Class classz, List paras)
throws DaoAccessException {
log.info("jcbksql-" + sql);
return getObject(sql, classz, paras.toArray());
}
@Override
public T getObject(String sql, Class classz,
Map paras) throws DaoAccessException {
log.info("jcbksql-" + sql);
T result = null;
try{
result = getNamedJdbcTemplate().queryForObject(sql, paras, new BeanPropertyRowMapper(classz));
}catch(EmptyResultDataAccessException e){
//
}
return result;
}
@Override
public List
/* , */
package com.sunshine.basic.dao;
import org.springframework.beans.BeansException;
import org.springframework.jdbc.core.JdbcTemplate;
import com.sunshine.basic.dao.AbstractJdbcCommDao;
import com.sunshine.basic.dao.parser.AbstractParser;
import com.sunshine.basic.dao.parser.Dialect;
import com.sunshine.basic.dao.parser.Parser;
import com.sunshine.basic.exception.DaoAccessException;
import com.sunshine.basic.tools.ApplicationContextTools;
/**
* JdbcAdapterDaoProxy ,
* @see com.sunshine.monitor.comm.dao.adapter.JdbcAdapterDaoProxy
* @author OY
*
*/
public abstract class AbstractJdbcAdapterDao extends AbstractJdbcCommDao {
/* */
private String jdbcTemplateName;
private Dialect dialect;
/**
* JdbcTemplate
* @param jdbcTemplateName
* @param dialect
*/
public AbstractJdbcAdapterDao(String jdbcTemplateName, Dialect dialect){
this.jdbcTemplateName = jdbcTemplateName;
this.dialect = dialect;
}
/* */
public final void setJdbcTemplateName(String jdbcTemplateName){
this.jdbcTemplateName = jdbcTemplateName;
}
@Override
public final JdbcTemplate getSubJdbcTemplate() throws DaoAccessException {
JdbcTemplate jdbcTemplate = null;
try {
jdbcTemplate = ApplicationContextTools.getBean(
this.jdbcTemplateName, JdbcTemplate.class);
if(jdbcTemplate == null)
throw new DaoAccessException("JdbcTemplate !");
} catch (BeansException e) {
e.printStackTrace();
throw new DaoAccessException("JdbcTemplate !");
}
return jdbcTemplate;
}
@Override
public Parser getParser() throws DaoAccessException {
return AbstractParser.newParser(this.dialect);
}
}
/*Oracle */
package com.sunshine.basic.dao.jdbc;
import org.springframework.stereotype.Repository;
import com.sunshine.basic.dao.AbstractJdbcAdapterDao;
import com.sunshine.basic.dao.parser.Dialect;
@Repository("oracleJdbcDao")
public class OracleJdbcDao extends AbstractJdbcAdapterDao {
public OracleJdbcDao(){
super("jdbcTemplate", Dialect.of("oracle"));
}
}
/*GreenPum */
package com.sunshine.basic.dao.jdbc;
import org.springframework.stereotype.Repository;
import com.sunshine.basic.dao.AbstractJdbcAdapterDao;
import com.sunshine.basic.dao.parser.Dialect;
/**
* @author oy
*
*/
@Repository("greenPlumJdbcDao")
public class GreenPlumJdbcDao extends AbstractJdbcAdapterDao {
public GreenPlumJdbcDao(){
super("gpJdbcTemplate",Dialect.of("postgresql"));
}
}
package com.sunshine.basic.dao.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
*
* @author oy
*
*/
public class JdbcAdapterDaoProxy implements MethodInterceptor{
private Object target;
public JdbcAdapterDaoProxy(){
}
public Object createInstance(Object target){
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
//
enhancer.setCallback(this);
//
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
}
인용 하 다.
데이터베이스 방언 및 SQL 지능 페이지
package com.sunshine.basic.dao.parser;
public interface Parser {
/**
* sql - ,
*
* @param sql sql
* @return count sql
*/
String getCountSql(String sql);
/**
* sql - ,
*
* @param sql sql
* @return sql
*/
String getPageSql(String sql);
/**
*
* @param sql
* @return
*/
String getPageSqlForPlace(String sql);
/**
*
* @return
*/
Dialect getDialect();
/**
*
* @param dialect
*/
void setDialect(Dialect dialect);
}
package com.sunshine.basic.dao.parser;
import com.sunshine.basic.dao.parser.impl.MysqlParser;
import com.sunshine.basic.dao.parser.impl.OracleParser;
import com.sunshine.basic.dao.parser.impl.PostgreSQLParser;
public abstract class AbstractParser implements Parser{
// SQL
public static final SqlParser sqlParser = new SqlParser();
private Dialect dialect;
public static final String END_INDEX_NAME="endIndex";
public static final String START_INDEX_NAME = "startIndex";
public Dialect getDialect(){
return dialect;
}
public void setDialect(Dialect dialect){
this.dialect = dialect;
}
public static Parser newParser(Dialect dialect) {
Parser parser = null;
switch (dialect) {
case postgresql:
parser = new PostgreSQLParser();
break;
case mysql:
parser = new MysqlParser();
break;
case oracle:
parser = new OracleParser();
break;
default:
break;
}
if(parser != null)
parser.setDialect(dialect);
return parser;
}
public String getCountSql(final String sql) {
return sqlParser.getSmartCountSql(sql);
}
public abstract String getPageSql(String sql);
}
package com.sunshine.basic.dao.parser.impl;
import com.sunshine.basic.dao.parser.AbstractParser;
public class OracleParser extends AbstractParser {
@Override
public String getPageSql(String sql) {
StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120);
sqlBuilder.append("select * from ( select tmp_page.*, rownum row_id from ( ");
sqlBuilder.append(sql);
sqlBuilder.append(" ) tmp_page where rownum <= ? ) where row_id > ?");
return sqlBuilder.toString();
}
@Override
public String getPageSqlForPlace(String sql) {
StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120);
sqlBuilder.append("select * from ( select tmp_page.*, rownum row_id from ( ");
sqlBuilder.append(sql);
sqlBuilder.append(" ) tmp_page where rownum <= :");
sqlBuilder.append(END_INDEX_NAME);
sqlBuilder.append(") where row_id > :");
sqlBuilder.append(START_INDEX_NAME);
return sqlBuilder.toString();
}
}
/* */
package com.sunshine.basic.dao.parser;
public enum Dialect {
mysql, oracle, postgresql;
public static Dialect of(String dialect) {
try {
Dialect d = Dialect.valueOf(dialect);
return d;
} catch (IllegalArgumentException e) {
String dialects = null;
for (Dialect d : Dialect.values()) {
if (dialects == null) {
dialects = d.toString();
} else {
dialects += "," + d;
}
}
throw new IllegalArgumentException(" dialect , [" + dialects + "]");
}
}
public static String[] dialects() {
Dialect[] dialects = Dialect.values();
String[] ds = new String[dialects.length];
for (int i = 0; i < dialects.length; i++) {
ds[i] = dialects[i].toString();
}
return ds;
}
public static String fromJdbcUrl(String jdbcUrl) {
String[] dialects = dialects();
for (String dialect : dialects) {
if (jdbcUrl.indexOf(":" + dialect + ":") != -1) {
return dialect;
}
}
return null;
}
}
/*SQL , jsqlparse.jar*/
package com.sunshine.basic.dao.parser;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.LateralSubSelect;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.select.SubJoin;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.statement.select.ValuesList;
import net.sf.jsqlparser.statement.select.WithItem;
import org.apache.log4j.Logger;
/**
* sql , count sql
*/
public class SqlParser {
private static final List COUNT_ITEM;
private static final Alias TABLE_ALIAS;
private Logger log = Logger.getLogger(SqlParser.class);
static {
COUNT_ITEM = new ArrayList();
COUNT_ITEM.add(new SelectExpressionItem(new Column("count(1)")));
TABLE_ALIAS = new Alias("table_count");
TABLE_ALIAS.setUseAs(false);
}
// sql
private Map CACHE = new ConcurrentHashMap();
public void isSupportedSql(String sql) {
if (sql.trim().toUpperCase().endsWith("FOR UPDATE")) {
throw new RuntimeException(" for update sql");
}
}
/**
* countSql
*
* @param sql
* @return
*/
public String getSmartCountSql(String sql) {
log.info("Sql parse before:" + sql);
// sql
isSupportedSql(sql);
if (CACHE.get(sql) != null) {
log.info("Count sql parse(Cache):" + CACHE.get(sql));
return CACHE.get(sql);
}
// SQL
Statement stmt = null;
try {
stmt = CCJSqlParserUtil.parse(sql);
} catch (Throwable e) {
// count
String countSql = getSimpleCountSql(sql);
CACHE.put(sql, countSql);
return countSql;
}
Select select = (Select) stmt;
SelectBody selectBody = select.getSelectBody();
// body- order by
processSelectBody(selectBody);
// with- order by
processWithItemsList(select.getWithItemsList());
// count
sqlToCount(select);
String result = select.toString();
CACHE.put(sql, result);
log.info("Sql parse after:" + sql);
return result;
}
/**
* Count-sql
* @param sql sql
* @return count sql
*/
public String getSimpleCountSql(final String sql) {
isSupportedSql(sql);
StringBuilder stringBuilder = new StringBuilder(sql.length() + 40);
stringBuilder.append("select count(*) from (");
stringBuilder.append(sql);
stringBuilder.append(") tmp_count");
return stringBuilder.toString();
}
/**
* sql count
* @param select
*/
public void sqlToCount(Select select) {
SelectBody selectBody = select.getSelectBody();
// count
if (selectBody instanceof PlainSelect && isSimpleCount((PlainSelect) selectBody)) {
((PlainSelect) selectBody).setSelectItems(COUNT_ITEM);
} else {
PlainSelect plainSelect = new PlainSelect();
SubSelect subSelect = new SubSelect();
subSelect.setSelectBody(selectBody);
subSelect.setAlias(TABLE_ALIAS);
plainSelect.setFromItem(subSelect);
plainSelect.setSelectItems(COUNT_ITEM);
select.setSelectBody(plainSelect);
}
}
/**
* count
* @param select
* @return
*/
public boolean isSimpleCount(PlainSelect select) {
// group by
if (select.getGroupByColumnReferences() != null) {
return false;
}
// distinct
if (select.getDistinct() != null) {
return false;
}
for (SelectItem item : select.getSelectItems()) {
//select ,
if (item.toString().contains("?")) {
return false;
}
// , ,
if (item instanceof SelectExpressionItem) {
if (((SelectExpressionItem) item).getExpression() instanceof Function) {
return false;
}
}
}
return true;
}
/**
* selectBody Order by
*
* @param selectBody
*/
public void processSelectBody(SelectBody selectBody) {
if (selectBody instanceof PlainSelect) {
processPlainSelect((PlainSelect) selectBody);
} else if (selectBody instanceof WithItem) {
WithItem withItem = (WithItem) selectBody;
if (withItem.getSelectBody() != null) {
processSelectBody(withItem.getSelectBody());
}
} else {
SetOperationList operationList = (SetOperationList) selectBody;
if (operationList.getPlainSelects() != null && operationList.getPlainSelects().size() > 0) {
List plainSelects = operationList.getPlainSelects();
for (PlainSelect plainSelect : plainSelects) {
processPlainSelect(plainSelect);
}
}
if (!orderByHashParameters(operationList.getOrderByElements())) {
operationList.setOrderByElements(null);
}
}
}
/**
* PlainSelect selectBody
*
* @param plainSelect
*/
public void processPlainSelect(PlainSelect plainSelect) {
if (!orderByHashParameters(plainSelect.getOrderByElements())) {
plainSelect.setOrderByElements(null);
}
if (plainSelect.getFromItem() != null) {
processFromItem(plainSelect.getFromItem());
}
if (plainSelect.getJoins() != null && plainSelect.getJoins().size() > 0) {
List joins = plainSelect.getJoins();
for (Join join : joins) {
if (join.getRightItem() != null) {
processFromItem(join.getRightItem());
}
}
}
}
/**
* WithItem
*
* @param withItemsList
*/
public void processWithItemsList(List withItemsList) {
if (withItemsList != null && withItemsList.size() > 0) {
for (WithItem item : withItemsList) {
processSelectBody(item.getSelectBody());
}
}
}
/**
*
*
* @param fromItem
*/
public void processFromItem(FromItem fromItem) {
if (fromItem instanceof SubJoin) {
SubJoin subJoin = (SubJoin) fromItem;
if (subJoin.getJoin() != null) {
if (subJoin.getJoin().getRightItem() != null) {
processFromItem(subJoin.getJoin().getRightItem());
}
}
if (subJoin.getLeft() != null) {
processFromItem(subJoin.getLeft());
}
} else if (fromItem instanceof SubSelect) {
SubSelect subSelect = (SubSelect) fromItem;
if (subSelect.getSelectBody() != null) {
processSelectBody(subSelect.getSelectBody());
}
} else if (fromItem instanceof ValuesList) {
} else if (fromItem instanceof LateralSubSelect) {
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
if (lateralSubSelect.getSubSelect() != null) {
SubSelect subSelect = lateralSubSelect.getSubSelect();
if (subSelect.getSelectBody() != null) {
processSelectBody(subSelect.getSelectBody());
}
}
}
//Table
}
/**
* Orderby ,
*
* @param orderByElements
* @return
*/
public boolean orderByHashParameters(List orderByElements) {
if (orderByElements == null) {
return false;
}
for (OrderByElement orderByElement : orderByElements) {
if (orderByElement.toString().contains("?")) {
return true;
}
}
return false;
}
public static void main(String[] args) {
String countSql = new SqlParser()
.getSmartCountSql("select count(t.hphm) as GCCS, t.hphm as HPHM, t.hpys as HPYS, t.hpzl as HPZL from veh_passrec t where t.hphm like ' A_____' and t.gcsj > '2010-02-18 00:00:00' and t.gcsj <= '2010-02-21 23:59:59' group by t.hphm, t.hpys, t.hpzl");
System.out.println(countSql);
}
}
/* */
package com.sunshine.basic.dao.page;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.sunshine.basic.dao.parser.Dialect;
/**
*
*/
public class PagingParameter implements Serializable{
private static final long serialVersionUID = -5871263750693828476L;
/** , -1, , */
private int curPage = -1;
/** , 0, , */
private int pageSize = 0;
/** */
private int totalRows = 0;
/**
* , , ,
*/
public PagingParameter(){
}
/**
*
* @param start
* @param pageSize
*/
public PagingParameter(int curPage,int pageSize, int totalRows){
this.curPage = curPage;
this.pageSize = pageSize;
this.totalRows = totalRows;
}
public int getTotalRows() {
return totalRows;
}
public int getCurPage() {
return curPage;
}
public void setCurPage(int curPage) {
this.curPage = curPage;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
}
/**
* , true( ) ,
*
* @return
*/
public boolean isInvalid() {
return curPage < 0 || pageSize <= 0;
}
/**
*
* @return
*/
public Map getStartAndEndRow(){
//
int totalPages = totalPage();
Map map = null;
//
int start = (curPage - 1) * pageSize;
//
int end = 0;
if (totalRows < pageSize) {
end = totalRows;
} else if ((totalRows % pageSize == 0)
|| (totalRows % pageSize != 0 && curPage < totalPages)) {
end = curPage * pageSize;
} else if (totalRows % pageSize != 0 && curPage == totalPages) {//
end = totalRows;
}
map = new HashMap();
map.put("start", start);
map.put("end", end);
return map ;
}
/**
*
* @return
*/
public int getEndRow(Dialect dialect){
int end = 0;
switch (dialect) {
case mysql:
end = pageSize;
break;
case postgresql:
end = pageSize;
break;
case oracle:
end = getOracleEndRow();
break;
default:
break;
}
return end;
}
public int getOracleEndRow(){
int end = 0;
int totalPages = totalPage();
if (totalRows < pageSize) {
end = totalRows;
} else if ((totalRows % pageSize == 0)
|| (totalRows % pageSize != 0 && curPage < totalPages)) {
end = curPage * pageSize;
} else if (totalRows % pageSize != 0 && curPage == totalPages) {//
end = totalRows;
}
return end;
}
/**
*
* @return
*/
public int getStartRow(){
return (curPage - 1) * pageSize;
}
/**
*
* @return
*/
public int totalPage(){
int totalPages = 0;
if (pageSize != -1) {
int pc = (int)Math.ceil(totalRows/pageSize);
totalPages = (pc == 0) ? 1 : pc;
} else {
totalPages = 1;
}
return totalPages;
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.