parent
9d36ad5abf
commit
d0b62adc54
@ -1,23 +0,0 @@ |
||||
package core.dao; |
||||
|
||||
import org.hibernate.SessionFactory; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.orm.hibernate5.HibernateTemplate; |
||||
import org.springframework.stereotype.Repository; |
||||
|
||||
/** |
||||
* Created by reborn on 2017/7/31. |
||||
*/ |
||||
|
||||
@Repository |
||||
public class BaseDao1 extends HibernateTemplate{ |
||||
|
||||
@Autowired |
||||
public BaseDao1(SessionFactory aliyun) { |
||||
super(aliyun); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -1,26 +0,0 @@ |
||||
package core.dao; |
||||
|
||||
import db.AbstractModel; |
||||
import org.hibernate.SessionFactory; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.dao.DataAccessException; |
||||
import org.springframework.orm.hibernate5.HibernateTemplate; |
||||
import org.springframework.stereotype.Repository; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
@Repository |
||||
public class BaseDao2 extends HibernateTemplate { |
||||
|
||||
@Autowired |
||||
public BaseDao2(SessionFactory huaWeiCloud) { |
||||
super(huaWeiCloud); |
||||
} |
||||
|
||||
public <T extends AbstractModel> void delete(Class<T> tClass, Serializable key) throws DataAccessException { |
||||
T model = load(tClass, key); |
||||
if (model != null) { |
||||
delete(model); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,69 @@ |
||||
package db; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class PageResult<T extends AbstractModel> { |
||||
private long count; |
||||
|
||||
private int currentPage; |
||||
|
||||
private List<T> datas; |
||||
|
||||
private int pageSize; |
||||
|
||||
private long pages; |
||||
|
||||
private Type type; |
||||
|
||||
private String errorMsg; |
||||
|
||||
/** |
||||
* |
||||
* @param count 总行数 |
||||
* @param currentPage 当前分页数 |
||||
* @param datas 数据 |
||||
* @param pageSize 分页大小 |
||||
* @param type 操作结果 |
||||
*/ |
||||
public PageResult(long count, int currentPage, List<T> datas, int pageSize, Type type) { |
||||
this.count = count; |
||||
this.currentPage = currentPage+1; |
||||
this.datas = datas; |
||||
this.pageSize = pageSize; |
||||
this.pages=count%pageSize==0?count/pageSize:count/pageSize+1; |
||||
this.type = type; |
||||
} |
||||
|
||||
public PageResult(Type type, String errorMsg) { |
||||
this.type = type; |
||||
this.errorMsg = errorMsg; |
||||
} |
||||
|
||||
public long getCount() { |
||||
return count; |
||||
} |
||||
|
||||
public int getCurrentPage() { |
||||
return currentPage; |
||||
} |
||||
|
||||
public List<T> getDatas() { |
||||
return datas; |
||||
} |
||||
|
||||
public Type getType() { |
||||
return type; |
||||
} |
||||
|
||||
public int getPageSize() { |
||||
return pageSize; |
||||
} |
||||
|
||||
public long getPages() { |
||||
return pages; |
||||
} |
||||
|
||||
public String getErrorMsg() { |
||||
return errorMsg; |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
package db; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
public enum Type implements Serializable { |
||||
success("成功"), |
||||
fail("失败") ; |
||||
private String desc; |
||||
|
||||
Type(String desc) { |
||||
this.desc = desc; |
||||
} |
||||
|
||||
public String getDesc() { |
||||
return desc; |
||||
} |
||||
} |
@ -0,0 +1,4 @@ |
||||
package db.annotation; |
||||
|
||||
public @interface BiliBili { |
||||
} |
@ -0,0 +1,7 @@ |
||||
package db.config; |
||||
|
||||
import org.springframework.orm.hibernate5.LocalSessionFactoryBean; |
||||
|
||||
public interface AddConfig { |
||||
void addConfig(LocalSessionFactoryBean bean); |
||||
} |
@ -0,0 +1,119 @@ |
||||
package db.model; |
||||
|
||||
import db.AbstractModel; |
||||
|
||||
import javax.persistence.*; |
||||
import java.io.Serializable; |
||||
import java.util.Objects; |
||||
|
||||
@Entity |
||||
@Table(name = "datasource", schema = "rootdb", catalog = "") |
||||
public class DataSourceModel extends AbstractModel { |
||||
private String dbDesc; |
||||
private String hostname; |
||||
private int dbPort; |
||||
private String username; |
||||
private String dbPassword; |
||||
private String dbName; |
||||
private String annotation; |
||||
|
||||
@Id |
||||
@Column(name = "db_desc", nullable = false, length = 10) |
||||
public String getDbDesc() { |
||||
return dbDesc; |
||||
} |
||||
|
||||
public void setDbDesc(String dbDesc) { |
||||
this.dbDesc = dbDesc; |
||||
} |
||||
|
||||
@Basic |
||||
@Column(name = "hostname", nullable = false, length = 32) |
||||
public String getHostname() { |
||||
return hostname; |
||||
} |
||||
|
||||
public void setHostname(String hostname) { |
||||
this.hostname = hostname; |
||||
} |
||||
|
||||
@Basic |
||||
@Column(name = "db_port", nullable = false) |
||||
public int getDbPort() { |
||||
return dbPort; |
||||
} |
||||
|
||||
public void setDbPort(int dbPort) { |
||||
this.dbPort = dbPort; |
||||
} |
||||
|
||||
@Basic |
||||
@Column(name = "username", nullable = false, length = 10) |
||||
public String getUsername() { |
||||
return username; |
||||
} |
||||
|
||||
public void setUsername(String username) { |
||||
this.username = username; |
||||
} |
||||
|
||||
@Basic |
||||
@Column(name = "db_password", nullable = false, length = 10) |
||||
public String getDbPassword() { |
||||
return dbPassword; |
||||
} |
||||
|
||||
public void setDbPassword(String dbPassword) { |
||||
this.dbPassword = dbPassword; |
||||
} |
||||
|
||||
@Basic |
||||
@Column(name = "db_name", nullable = false, length = 10) |
||||
public String getDbName() { |
||||
return dbName; |
||||
} |
||||
|
||||
public void setDbName(String dbName) { |
||||
this.dbName = dbName; |
||||
} |
||||
|
||||
@Basic |
||||
@Column(name = "annotation", nullable = true, length = 10) |
||||
public String getAnnotation() { |
||||
return annotation; |
||||
} |
||||
|
||||
public void setAnnotation(String annotation) { |
||||
this.annotation = annotation; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (o == null || getClass() != o.getClass()) return false; |
||||
DataSourceModel that = (DataSourceModel) o; |
||||
return dbPort == that.dbPort && |
||||
Objects.equals(dbDesc, that.dbDesc) && |
||||
Objects.equals(hostname, that.hostname) && |
||||
Objects.equals(username, that.username) && |
||||
Objects.equals(dbPassword, that.dbPassword) && |
||||
Objects.equals(dbName, that.dbName) && |
||||
Objects.equals(annotation, that.annotation); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
|
||||
return Objects.hash(dbDesc, hostname, dbPort, username, dbPassword, dbName, annotation); |
||||
} |
||||
|
||||
@Override |
||||
public Serializable primaryKey() { |
||||
return getDbDesc(); |
||||
} |
||||
|
||||
@Override |
||||
public String tableNote() { |
||||
return "数据源"; |
||||
} |
||||
} |
@ -1,4 +1,4 @@ |
||||
package db.model; |
||||
package db.model.bilibili; |
||||
|
||||
import db.AbstractModel; |
||||
|
@ -1,11 +1,13 @@ |
||||
package db.model; |
||||
package db.model.bilibili; |
||||
|
||||
import db.AbstractModel; |
||||
import db.annotation.BiliBili; |
||||
|
||||
import javax.persistence.*; |
||||
import java.io.Serializable; |
||||
import java.util.Objects; |
||||
|
||||
@BiliBili |
||||
@Entity |
||||
@Table(name = "data", schema = "bilibili", catalog = "bilibili") |
||||
public class DataModel extends AbstractModel { |
@ -1,4 +1,4 @@ |
||||
package db.model; |
||||
package db.model.bilibili; |
||||
|
||||
import db.AbstractModel; |
||||
|
@ -1,4 +1,4 @@ |
||||
package db.model; |
||||
package db.model.bilibili; |
||||
|
||||
import db.AbstractModel; |
||||
|
@ -0,0 +1,124 @@ |
||||
package db.util; |
||||
|
||||
import org.apache.commons.lang3.ArrayUtils; |
||||
import org.springframework.beans.factory.BeanDefinitionStoreException; |
||||
import org.springframework.context.ResourceLoaderAware; |
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.core.io.ResourceLoader; |
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; |
||||
import org.springframework.core.io.support.ResourcePatternResolver; |
||||
import org.springframework.core.io.support.ResourcePatternUtils; |
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory; |
||||
import org.springframework.core.type.classreading.MetadataReader; |
||||
import org.springframework.core.type.classreading.MetadataReaderFactory; |
||||
import org.springframework.core.type.filter.AnnotationTypeFilter; |
||||
import org.springframework.core.type.filter.TypeFilter; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.util.SystemPropertyUtils; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.annotation.Annotation; |
||||
import java.util.HashSet; |
||||
import java.util.LinkedList; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
public class ClassScaner implements ResourceLoaderAware { |
||||
//保存过滤规则要排除的注解
|
||||
private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>(); |
||||
private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>(); |
||||
|
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); |
||||
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); |
||||
|
||||
public static Set<Class> scan(String[] basePackages, |
||||
Class<? extends Annotation>... annotations) { |
||||
ClassScaner cs = new ClassScaner(); |
||||
|
||||
if(ArrayUtils.isNotEmpty(annotations)) { |
||||
for (Class anno : annotations) { |
||||
cs.addIncludeFilter(new AnnotationTypeFilter(anno)); |
||||
} |
||||
} |
||||
|
||||
Set<Class> classes = new HashSet<Class>(); |
||||
for (String s : basePackages) |
||||
classes.addAll(cs.doScan(s)); |
||||
return classes; |
||||
} |
||||
|
||||
public static Set<Class> scan(String basePackages, Class<? extends Annotation>... annotations) { |
||||
return ClassScaner.scan(StringUtils.tokenizeToStringArray(basePackages, ",; \t\n"), annotations); |
||||
} |
||||
|
||||
public final ResourceLoader getResourceLoader() { |
||||
return this.resourcePatternResolver; |
||||
} |
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) { |
||||
this.resourcePatternResolver = ResourcePatternUtils |
||||
.getResourcePatternResolver(resourceLoader); |
||||
this.metadataReaderFactory = new CachingMetadataReaderFactory( |
||||
resourceLoader); |
||||
} |
||||
|
||||
public void addIncludeFilter(TypeFilter includeFilter) { |
||||
this.includeFilters.add(includeFilter); |
||||
} |
||||
|
||||
public void addExcludeFilter(TypeFilter excludeFilter) { |
||||
this.excludeFilters.add(0, excludeFilter); |
||||
} |
||||
|
||||
public void resetFilters(boolean useDefaultFilters) { |
||||
this.includeFilters.clear(); |
||||
this.excludeFilters.clear(); |
||||
} |
||||
|
||||
public Set<Class> doScan(String basePackage) { |
||||
Set<Class> classes = new HashSet<Class>(); |
||||
try { |
||||
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX |
||||
+ org.springframework.util.ClassUtils |
||||
.convertClassNameToResourcePath(SystemPropertyUtils |
||||
.resolvePlaceholders(basePackage)) |
||||
+ "/**/*.class"; |
||||
Resource[] resources = this.resourcePatternResolver |
||||
.getResources(packageSearchPath); |
||||
|
||||
for (int i = 0; i < resources.length; i++) { |
||||
Resource resource = resources[i]; |
||||
if (resource.isReadable()) { |
||||
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); |
||||
if ((includeFilters.size() == 0 && excludeFilters.size() == 0) |
||||
|| matches(metadataReader)) { |
||||
try { |
||||
classes.add(Class.forName(metadataReader |
||||
.getClassMetadata().getClassName())); |
||||
} catch (ClassNotFoundException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} catch (IOException ex) { |
||||
throw new BeanDefinitionStoreException( |
||||
"I/O failure during classpath scanning", ex); |
||||
} |
||||
return classes; |
||||
} |
||||
|
||||
protected boolean matches(MetadataReader metadataReader) throws IOException { |
||||
for (TypeFilter tf : this.excludeFilters) { |
||||
if (tf.match(metadataReader, this.metadataReaderFactory)) { |
||||
return false; |
||||
} |
||||
} |
||||
for (TypeFilter tf : this.includeFilters) { |
||||
if (tf.match(metadataReader, this.metadataReaderFactory)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
package web.controller; |
||||
|
||||
import db.AbstractModel; |
||||
import db.DBAction; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import web.service.BiliService; |
||||
|
||||
public class BiliController<T extends AbstractModel> extends BaseController<T,BiliService>{ |
||||
|
||||
@Override |
||||
@Autowired |
||||
protected void setService(BiliService service) { |
||||
this.service=service; |
||||
} |
||||
|
||||
@Override |
||||
protected boolean checkAction(DBAction action) { |
||||
return false; |
||||
} |
||||
} |
@ -1,18 +0,0 @@ |
||||
package web.controller; |
||||
|
||||
import db.DBAction; |
||||
import db.model.DataModel; |
||||
import org.springframework.stereotype.Controller; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
||||
@Controller |
||||
@RequestMapping("/comment") |
||||
public class CommentController extends BaseController<DataModel>{ |
||||
|
||||
|
||||
|
||||
@Override |
||||
public boolean checkAction(DBAction action) { |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,47 @@ |
||||
package web.controller; |
||||
|
||||
import core.service.BaseService; |
||||
import db.AbstractModel; |
||||
import db.DBAction; |
||||
import db.PageResult; |
||||
import db.Type; |
||||
import org.springframework.dao.DataAccessException; |
||||
import org.springframework.ui.Model; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
||||
import java.util.List; |
||||
|
||||
public abstract class TableController<T extends AbstractModel,E extends BaseService> extends BaseController<T,E> { |
||||
@RequestMapping("table") |
||||
public <T extends AbstractModel> String find(Model model, T queryCommand, @RequestParam Integer firstResult, @RequestParam Integer maxResults){ |
||||
DBAction action=DBAction.R; |
||||
log.info(queryCommand.tableNote()+ "进行批量" + action.getCh() + "操作请求"); |
||||
PageResult result; |
||||
if(checkAction(action)) { |
||||
try { |
||||
Long rowCount=service.rowCount(queryCommand.getClass()); |
||||
if(rowCount>0) { |
||||
List list = service.find(queryCommand, firstResult*maxResults, maxResults); |
||||
result=new PageResult<T>(rowCount, firstResult,list,maxResults , Type.success); |
||||
}else{ |
||||
result=new PageResult(Type.fail,"没有记录"); |
||||
} |
||||
} catch (DataAccessException e) { |
||||
log.error(e); |
||||
result=new PageResult(Type.fail,"非法操作"); |
||||
} |
||||
}else{ |
||||
result=new PageResult(Type.fail,queryCommand.tableNote() + "不允许" + action.getCh() + "操作"); |
||||
} |
||||
|
||||
model.addAttribute("datas", result); |
||||
return "table"; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected boolean checkAction(DBAction action) { |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
package web.html; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public enum ElementId { |
||||
menu("menu_"), |
||||
button("btn_"), |
||||
iframe("iframe_") |
||||
; |
||||
|
||||
private String id; |
||||
|
||||
ElementId(String id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
public static Map<String,ElementId> getAll(){ |
||||
Map<String,ElementId> map=new HashMap<>(); |
||||
for(ElementId id:ElementId.values()){ |
||||
map.put(id.name(),id); |
||||
} |
||||
return map; |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
package web.service; |
||||
|
||||
import core.service.BaseService; |
||||
import db.config.HibernateConfig; |
||||
import org.springframework.orm.hibernate5.HibernateTemplate; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
@Service |
||||
public class BiliService extends BaseService { |
||||
@Override |
||||
protected HibernateTemplate getHibernateTemplate() { |
||||
return HibernateConfig.get("test2"); |
||||
} |
||||
} |
@ -1,16 +1,8 @@ |
||||
#-----------------------hibernate\u914D\u7F6E----------------------------- |
||||
#hibernate\u914D\u7F6E |
||||
db_url=jdbc:mysql://mysql.sukura.top:8635/rootdb?serverTimezone=UTC&useSSL=false |
||||
db_username=sukura |
||||
db_password=Luffy9412! |
||||
hibernate.dialect=org.hibernate.dialect.MySQL57Dialect |
||||
hibernate.connection.driver_class=com.mysql.cj.jdbc.Driver |
||||
#\u6570\u636E\u6E901 |
||||
hibernate.connection.url=jdbc:mysql://sukura.top:3306/bilibili?serverTimezone=UTC&useSSL=false |
||||
hibernate.connection.username=sukura |
||||
hibernate.connection.password=@ |
||||
#\u6570\u636E\u6E902 |
||||
hibernate.connection.url2=jdbc:mysql://mysql.sukura.top:8635/bilibili?serverTimezone=UTC&useSSL=false |
||||
hibernate.connection.username2=sukura |
||||
hibernate.connection.password2=Luffy9412! |
||||
#-----------------------DruidDataSource\u914D\u7F6E----------------------- |
||||
#DruidDataSource\u914D\u7F6E |
||||
druid.maxActive=20 |
||||
|
||||
spring.scan=core,web,db |
||||
sessionFactory.scan=db.model |
@ -0,0 +1,13 @@ |
||||
|
||||
|
||||
# |
||||
# |
||||
##\u6570\u636E\u6E901 |
||||
#hibernate.connection.url1=jdbc:mysql://sukura.top:3306/bilibili?serverTimezone=UTC&useSSL=false |
||||
#hibernate.connection.username1=sukura |
||||
#hibernate.connection.password1=@ |
||||
# |
||||
##\u6570\u636E\u6E902 |
||||
#hibernate.connection.url2=jdbc:mysql://mysql.sukura.top:8635/bilibili?serverTimezone=UTC&useSSL=false |
||||
#hibernate.connection.username2=sukura |
||||
#hibernate.connection.password2=Luffy9412! |
@ -1,11 +1,87 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!--输出,条件,迭代标签库--> |
||||
<%@ page pageEncoding="utf-8"%> |
||||
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> |
||||
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <!--输出,条件,迭代标签库--> |
||||
<%@ page pageEncoding="utf-8" %> |
||||
<head> |
||||
<c:import url="head.jsp"/> |
||||
<script> |
||||
$(function () { |
||||
$("#pageButton button").click(function () { |
||||
$("[name=firstResult]").val($(this).val()); |
||||
$('#command').submit(); |
||||
}); |
||||
}); |
||||
</script> |
||||
</head> |
||||
<body> |
||||
table |
||||
<c:choose> |
||||
<c:when test="${datas.type=='success'}"> |
||||
<table class="table"> |
||||
<thead> |
||||
<tr> |
||||
<th scope="col">cid</th> |
||||
<th scope="col">aid</th> |
||||
<th scope="col">title</th> |
||||
<th scope="col">subtitle</th> |
||||
<th scope="col">author</th> |
||||
|
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<c:forEach items="${datas.datas}" var="data"> |
||||
<tr> |
||||
<td>${data.cid}</td> |
||||
<td>${data.aid}</td> |
||||
<td>${data.title}</td> |
||||
<td>${data.subtitle}</td> |
||||
<td>${data.author}</td> |
||||
</tr> |
||||
|
||||
</c:forEach> |
||||
|
||||
</tbody> |
||||
</table> |
||||
|
||||
<form:form action="/data/table"> |
||||
<input type="hidden" name="firstResult" value="0"/> |
||||
<input type="hidden" name="maxResults" value="${datas.pageSize}"/> |
||||
<div class="row"> |
||||
<div class="col-sm-6"> |
||||
<p class="text-justify font-weight-bold"> |
||||
Showing ${(datas.currentPage-1)*datas.pageSize+1} to ${datas.currentPage*datas.pageSize} |
||||
of ${datas.count} entries |
||||
</p> |
||||
</div> |
||||
<div class="col-sm-6"> |
||||
<div id="pageButton" class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups"> |
||||
<div class="btn-group mr-2" role="group"> |
||||
<button value="0" type="button" class="btn btn-secondary">首页</button> |
||||
<button value="${datas.currentPage-2}" type="button" class="btn btn-secondary" |
||||
<c:if test="${datas.currentPage-2==-1}">disabled</c:if>>上一页 |
||||
</button> |
||||
<button value="${datas.currentPage}" type="button" class="btn btn-secondary">下一页</button> |
||||
<button value="${datas.pages}" type="button" class="btn btn-secondary">尾页</button> |
||||
</div> |
||||
|
||||
<div class="btn-group mr-2" role="group"> |
||||
<c:forEach begin="${datas.currentPage+1}" |
||||
end="${datas.currentPage+9}" var="i"> |
||||
<c:if test="${i<=datas.pages}"> |
||||
<button value="${i}" type="button" class="btn btn-secondary">${i}</button> |
||||
</c:if> |
||||
</c:forEach> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</form:form> |
||||
</c:when> |
||||
<c:otherwise> |
||||
<div class="alert alert-danger text-center" role="alert"> |
||||
请求数据失败 |
||||
</div> |
||||
</c:otherwise> |
||||
</c:choose> |
||||
</body> |
||||
</html> |
||||
|
Loading…
Reference in new issue