标签:rop not amp ring OLE 完成后 before chm enc
已知当前页pageNum和总页数totalPages,根据每页要求显示的页码列表的条数,得出页码列表的头startPage和尾endPage,在页面循环列表,即可展示出分页条。
分页列表头和尾的确定:假设页面要求显示10个页码,那么可以选择以当前页前4后5的显示方式,确定显示方式后,便可以计算头尾以构建分页列表。
Integer startPage = pageNum - 4;
Integer endPage = pageNum + 5;
if (startPage < 1){ //判断列表头startPage是否 < 1
startPage = 1;
endPage = startPage + 9;
}
if (endPage > totalPage){ //判断列表尾endPage是否 > totalPages
endPage = totalPage;
startPage = endPage - 9;
}
在页面获取以startPage为头endPage为尾的列表,并循环展示分页条
前端请求参数:pageNo、pageSize、QueryParams
后端响应数据:
html异步请求:
PageBean<T> {pageNo,pageSize,totalCount,totalPage,List<T> result,QueryParams}
可以在js中定义startPage和endPage
模板页同步请求:
PageBean<T> {pageNo,pageSize,totalCount,totalPage,List<T> result,QueryParams,startPage,endPage}
是否选中状态的通用思路:定义一个变量n记录选中状态的状态值,然后把当前变量与n比较,如果当前变量等于n记录的选中状态值,那么当前变量即选中状态
这里循环页码列表获取的变量page和当前页pageNum(记录选中状态的变量n)比较,如果page==pageNum,那么page对应的页码列表中页码即开启选中状态
<li th:class="${page==pageNo?‘active‘:‘‘}" th:each="page:${#numbers.sequence(startPage,endPage)}">
<a th:href="${#strings.replace(url,‘&pageNo=‘+pageNo,‘&pageNo=‘+page)}" th:text="${page}"></a>
</li>
引入分页助手
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
增强
thymeleaf与vue.js不同之处在于thymeleaf是在服务端渲染完成后,再将静态页面发给前台,相比前端vue.js发送异步请求获取数据后,再在前台进行渲染的情况, thymeleaf不会出现页面内容延迟加载的状况;
thymeleaf与jsp一样, 都是服务端渲染页面, 但thymeleaf相比jsp具有更强大的功能, 同时thymeleaf也是springboot官方推荐的渲染引擎, thymeleaf可以类比为更高级的jsp
添加thymeleaf依赖
<dependencies>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
</dependencies>
在applicationContext-thymeleaf.xml中配置模版引擎、视图解析器、模版解析器
<!-- 配置模板引擎 -->
<bean id="templateEngine"
class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver"/>
</bean>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
<!-- 配置模板解析器 -->
<bean id="templateResolver"
class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateMode" value="HTML"/>
</bean>
在webapp/WEB-INF目录下创建模板资源test.html
创建上下文对象Context, 用于向模版传递数据模型Map
//1. 创建上下文对象,传递数据模型
Context context = new Context();
Map<String,Object> dataModel = new HashMap<>();
//查询页面渲染需要的数据(主要业务逻辑,此处略...)
dataModel.put("name",object);
context.setVariables(dataModel);
创建目标文件输出流对象PrintWriter,调用模板引擎的process方法向生成静态页面目标文件
标签 | 说明 | 示例 |
---|---|---|
th:text | 指定文本内容 | <p th:text="${collect.description}"></p> |
th:utext | 支持html内容渲染 | <p th:utext="${htmlcontent}"></p> |
th:each | 1. 循环列表,userStat为循环状态量, 有index/count/current/even/odd/first/last等属性;2. 循环map集合,param.key、param.value分别获取map的键值 | <tr th:each="user:${users}"></tr>或者<tr th:each="param : ${params}" th:text = "${param.key + ‘:‘ + param.value}"></tr> |
th:if | 判断是否显示当前标签 | <a th:if="${userId == collect.userId}" > |
th:href | 链接地址 | <a th:href="${url}"/> |
th:src | 图片类地址引入 | <img th:src="${user.image}" /> |
th:inline | 定义js脚本可以使用渲染变量数据,使用方法:url = url.replace("&pageNo="+/星号[[${pageNo}]]星号/, "&pageTo="+pageTo) | <script th:inline="javascript"> |
numbers.formatDecimal | 保留两位小数 | ${#numbers.formatDecimal(arg,0,2) } |
numbers.sequence | 以startPage、endPage为头尾生成列表,默认步长值为1 | ${#numbers.sequence(startPage,endPage)} |
strings.replace | 替换字符串 | ${#strings.replace(url,‘abc‘,‘cba‘)} |
strings.startWith | 判断字符串是否以某子串开头(boolean) | ${#strings.startsWith(url,‘http‘)} |
strings.substring | 截取字符串子串,指定开始索引 | ${#strings.substring(url,5) |
maps.containsKey | 判断Map集合是否包含某个key | ${#maps.containsKey(searchMap,‘category‘)} |
<!-- 连接redis服务器 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!-- 引入spring-data-redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
SpringDataRedis底层封装了jedis,所以先配置JedisConnectionFactory,再注入到RedisTemplate中
<!-- Jedis连接配置对象JedisPoolConfig -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
</bean>
<!-- Jedis连接工厂JedisConnectionFactory -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/>
<!-- spring提供的模板工具redisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>
对象操作:boundValueOps
public void setValue(){
redisTemplate.boundValueOps("name").set("青橙电商");
}
public void getValue(){
String name = (String) redisTemplate.boundValueOps("name").get();
System.out.println(name);
}
public void deleValue(){
redisTemplate.delete("name");
}
Set集合操作:boundSetOps
public void setValue(){
redisTemplate.boundSetOps("nameSet").add("曹操");
redisTemplate.boundSetOps("nameSet").add("刘备");
redisTemplate.boundSetOps("nameSet").add("孙权");
}
public void getValue(){
Set nameSet = redisTemplate.boundSetOps("nameSet").members();
System.out.println(nameSet);
}
public void deleValue(){
redisTemplate.boundSetOps("nameSet").remove("曹操");
System.out.println(redisTemplate.boundSetOps("nameSet").members());
?
redisTemplate.delete("nameSet");
}
Map集合操作:boundHashOps
public void setValue(){
redisTemplate.boundHashOps("nameHash").put("0","唐僧");
Map<String,String> map = new HashMap();
map.put("1","悟空");
map.put("2","八戒");
map.put("3","沙僧");
redisTemplate.boundHashOps("nameHash").putAll(map);
}
public void getValue(){
String name = (String) redisTemplate.boundHashOps("nameHash").get("1");
System.out.println(name);
}
public void deleValue(){
redisTemplate.boundHashOps("nameHash").delete("2");
System.out.println(redisTemplate.boundHashOps("nameHash").values());
}
有序队列操作(存取顺序):boundListOps
public void setValue(){
redisTemplate.boundListOps("nameList").rightPush("中间值");
redisTemplate.boundListOps("nameList").rightPush("右压栈");
redisTemplate.boundListOps("nameList").leftPush("左压栈");
redisTemplate.boundListOps("nameList").rightPush("测试删除的索引位置");
redisTemplate.boundListOps("nameList").rightPush("测试删除");
redisTemplate.boundListOps("nameList").rightPush("测试删除");
}
public void getValue(){
List nameList = redisTemplate.boundListOps("nameList").range(0, -1);
System.out.println(nameList);
//按索引取值
String valueOfIndex = (String) redisTemplate.boundListOps("nameList").index(1);
System.out.println(valueOfIndex);
}
public void deleValue(){
//remove(删除的元素个数, 删除的元素值); 按索引从小到大查询指定个数的元素并删除
redisTemplate.boundListOps("nameList").remove(2,"测试删除");
System.out.println(redisTemplate.boundListOps("nameList").range(0,-1));
}
有序队列操作(需要经常发生顺序变动的情况):boundZSetOps
public void setValue(){
redisTemplate.boundZSetOps("nameZset").add("曹操",10000);
redisTemplate.boundZSetOps("nameZset").add("刘备",1000);
redisTemplate.boundZSetOps("nameZset").add("孙权",10);
}
public void getValue(){
//分数由低到高排序(默认)
Set<String> nameZset1 = redisTemplate.boundZSetOps("nameZset").range(0, -1);
System.out.println(nameZset1);
//分数由高到低排序(逆向)
Set<String> nameZset2 = redisTemplate.boundZSetOps("nameZset").reverseRange(0, -1);
System.out.println(nameZset2);
//带分数取值
Set<ZSetOperations.TypedTuple> nameTupleSet = redisTemplate.boundZSetOps("nameZset").rangeWithScores(0, -1);
for (ZSetOperations.TypedTuple nameTuple : nameTupleSet) {
System.out.println(nameTuple.getValue()+"..."+nameTuple.getScore());
}
}
public void incrementScore(){
redisTemplate.boundZSetOps("nameZset").incrementScore("孙权",1190);
System.out.println(redisTemplate.boundZSetOps("nameZset").range(0,-1));
}
public void deleValue(){
redisTemplate.boundZSetOps("nameZset").remove("孙权");
System.out.println(redisTemplate.boundZSetOps("nameZset").range(0,-1));
}
通用操作:
redisTemplate. delete(redisKey); 删除redisKey-value的方法 ; . redisTemplate. boundXxxOps(). expire(long , TimeUnit); 指定大Key的存活时间(短信验证码)
取不到对象, 返回null; 取不到集合, 返回[ ]
LocalDate不可用作前端传参,可以用String接收日期对象,再用LocalDate转换
LocalDate:表示默认格式yyyy-MM-dd的日期对象
LocalDate today = LocalDate.now():获取当前日期对象
LocalDate firstDayOf2019 = LocalDate.of(2019, Month.JANUARY, 1):获取指定日期对象
LocalTime:表示默认格式hh:mm:ss.zzz的时间对象
LocalTime time = LocalTime.now():获取当前时间对象
LocalTime specTime = LocalTime.of(23,23,23,23):获取指定时间对象23:23:23.023
LocalDateTime:表示日期+时间对象
LocalDateTime time = LocalDateTime.now():获取当前日期时间对象
LocalDateTime firstDayOf2019 = LocalDate.of(2019, Month.JANUARY, 1,0,0,0,0):获取指定日期时间对象
API | 说明 |
---|---|
LocalDate#isBefore(LocalDate date) | 判断是否在指定日期之前 |
LocalDate#plusDays/plusWeeks/plusMonths/minus.. | 从当前日期加减日、周、月后得到日期 |
Period period LocalDate#until(LocalDate date) | 获取到指定日期之间的天数 |
LocalDate#format(DateTimeFormatter.ofPattern("dd-MM-yyyy")) | 按指定格式格式化日期对象 |
LocalDate.parse("yyyy-MM-dd") | 解析日期字符串 |
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.0.3</version>
</dependency>
accessKeyId=LTAIfWgh9uJxqyJM
accessSecret=NMzCzy7mGry292XYlaTRxVmRVOsDL7
#短信模版号
smsCode=SMS_173341860
#生成的验证码
param={"code":"[value]"}
public class SmsUtil {
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.version}</version>
</dependency>
<!--基本配置:
1. 非目标资源解除拦截规则、目标资源拦截规则(<http>)
2. 认证管理器:自定义认证信息提供者(UserDetailsService);密码加密策略(BCrypt)-->
?
<!-- 1. 配置页面的拦截规则 -->
<!-- 1.1 解除非目标资源的拦截规则 -->
<http pattern="/login.html" security="none"></http>
<http pattern="/login_error.html" security="none"></http>
<!-- 1.2 配置目标资源(所有资源)必须拥有ROLE_ADMIN的角色才能访问 -->
<http>
<intercept-url pattern="/**" access="hasRole(‘ROLE_ADMIN‘)"/>
<!-- 指定登陆页面/目标访问页面/认证失败页面, 所有的页面必须使用绝对路径配置 -->
<form-login login-page="/login.html" default-target-url="/index.html" authentication-failure-forward-url="/login_error.html" />
<!-- 退出登录 -->
<logout />
<!-- 关闭csrf验证: 跨站请求伪造,csrf会随机产生一个token放到security提供的默认表单中,因为静态页无法动态生成token,所以将此功能关闭。一般静态页采用图形验证码的方式实现防止跨域请求伪造的功能。 -->
<csrf disabled="true"/>
</http>
?
<!-- 2. 配置认证管理器,获取来自数据库的认证信息 -->
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref="bcryptEncoder"></password-encoder>
</authentication-provider>
</authentication-manager>
<!-- 2.1 配置自定义认证信息提供者UserDetailsService -->
<beans:bean id="userDetailsService" class="com.qingcheng.demo.UserDetailsServiceImpl"></beans:bean>
<!-- 2.2 加密策略:指定由spring-security提供的相应的解密类 -->
<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>
</beans:beans>
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
?
import java.util.ArrayList;
import java.util.List;
?
/** UserDetailsService是spring-security提供的用于从数据库获取用户认证信息,并用UserDatils接口把"认证信息"传给认证管理器的工具接口
*/
public class UserDetailsServiceImpl implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
?
//参数三为用户所具有的认证角色集合
return new User(username,"$2a$10$amAQ3ClrcXV5K9gg6fsbfuUtdgliLTGvfzZuN3toBDAkbSK1nQliC",
grantedAuthorities);
}
}
Collection体系集合
使用默认方法stream()生成流, default Stream<E> stream()
Map体系集合
把Map转成Set集合,间接的生成流
数组
通过Stream静态方法 Stream.of(T... values) 生成流
public class StreamDemo {
public static void main(String[] args) {
//Collection体系的集合可以使用默认方法stream()生成流
List<String> list = new ArrayList<String>();
Stream<String> listStream = list.stream();
Set<String> set = new HashSet<String>();
Stream<String> setStream = set.stream();
?
//Map体系的集合间接的生成流
Map<String,Integer> map = new HashMap<String, Integer>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
?
//数组可以通过Stream接口的静态方法of(T... values)生成流
String[] strArray = {"hello","world","java"};
Stream<String> strArrayStream = Stream.of(strArray);
Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
Stream<Integer> intStream = Stream.of(10, 20, 30);
}
}
方法名 | 说明 |
---|---|
Stream<T> filter(Predicate predicate) | 用于对流中的数据进行过滤 |
Stream<T> limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
Stream<T> skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
static <T> Stream<T> concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
Stream<T> distinct() | 返回由该流的不同元素(根据Object.equals(Object) )组成的流 |
Stream<T> sorted() | 返回由此流的元素组成的流,根据自然顺序排序 |
Stream<T> sorted(Comparator comparator) | 返回由该流的元素组成的流,根据提供的Comparator进行排序 |
<R> Stream<R> map(Function mapper) | 返回由给定函数应用于此流的元素的结果组成的流 |
IntStream mapToInt(ToIntFunction mapper) | 返回一个IntStream其中包含将给定函数应用于此流的元素的结果 |
void forEach(Consumer action) | 对此流的每个元素执行操作 |
List collect(Collectors. toList()) | 把元素收集到List集合中 |
Set collect(Collectors. toSet()) | 把元素收集到Set集合中 |
Map collect(Collectors. toMap(Function keyMapper,Function valueMapper)) | 把元素收集到Map集合中:(keyMapper,valueMapper)分别表示从流中元素获取key和value的方法 |
filter、skip、limit、forEach、collect
public class StreamDemo01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("张敏");
list.add("张无忌");
//需求1:把list集合中以张开头的,长度为3的元素在控制台输出
list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
//需求2:跳过2个元素,把剩下的元素中前2个取出存入集合中
List newList = list.stream().skip(2).limit(2).collect(Collectors.toList);
}
}
map、mapToInt —— IntStream. min() max() sum();
public class StreamDemo05 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("10");
list.add("20");
list.add("30");
list.add("40");
list.add("50");
//int sum() 返回此流中元素的总和
int result = list.stream().mapToInt(Integer::parseInt).sum();
System.out.println(result);
}
}
Mongodb存储的数据是JSON格式的,相比较redis而言可以存储大的文件数据。一方面mongodb可以灵活存储json,另一方面存储的数据相比于数据库的核心数据不太重要,且没有事务管理要求。
? 1. model
? 2. dao
public interface CmsPageRepository extends MongoRepository<CmsPage,String> {
}
? 3. 基本方法
//1. 查询所有
List<CmsPage> all = cmsPageRepository.findAll();
?
//2. 分页查询
int page = 0; //页码从0开始
int size = 10;
Pageable pageable = PageRequest.of(page,size);
Page<CmsPage> all = cmsPageRepository.findAll(pageable);
List<CmsPage> cmsPageList = all.getContent(); //获取数据
long total = all.getTotalElements(); //获取记录数
?
//3. 条件查询
//创建条件值对象
CmsPage cmsPage = new CmsPage();
//设置条件值
cmsPage.setSiteId("5a751fab6abb5044e0d19ea1");
cmsPage.setTemplateId("5a962b52b00ffc514038faf7");
cmsPage.setPageAliase("导航");
//ExampleMatcher.GenericPropertyMatchers.contains() 包含关键字"导航"匹配
//ExampleMatcher.GenericPropertyMatchers.startsWith() 前缀匹配
ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains()); // 设置pageAliase字段模糊匹配
//创建条件实例
Example<CmsPage> example = Example.of(cmsPage,exampleMatcher);
Page<CmsPage> all = cmsPageRepository.findAll(example, pagebale);
?
//4. 添加
CmsPage cmsPage = cmsPageRepository.save(cmsPage);
?
//根据id查询
Optional<CmsPage> optional = cmsPageRepository.findById(id);
if (optional.isPresent()){
CmsPage cmsPage = optional.get();
return cmsPage;
}
return null;
GridFS是Mongodb提供的用于持久化存储文件的模块。它的工作原理是将文件按256kb的大小分割进行存储,GridFS用两个collection存储文件,一个是chunks,用于存储文件的二进制数据,一个是files,用于存储文件的元数据(文件名称、块大小、上传时间等)
1. GridFS存储文件
GridFS获取文件
? OpenAPI规范(OpenAPI Specification 简称OAS)是Linux基金会的一个项目,试图通过定义一种用来描述API格式或API定义的语言,来规范RESTful服务开发过程
? Swagger是全球最大的OpenAPI规范(OAS)API开发工具框架,支持从设计和文档到测试和部署的整个API生命周期的开发。Spring Boot 可以集成Swagger,生成Swagger接口。
注解 | 说明 |
---|---|
@Api | 修饰整个类,描述Controller的作用 |
@ApiOperation | 描述一个类的一个方法,或者说一个接口 |
@ApiParam | 单个参数描述 |
@ApiModel | 用对象来接收参数 |
@ApiModelProperty | 用对象接收参数时,描述对象的一个字段 |
@ApiResponse | HTTP响应其中1个描述 |
@ApiResponses | HTTP响应整体描述 |
@ApiError | 发生错误返回的信息 |
@ApiImplicitParam | 一个请求参数 |
@ApiImplicitParams | 多个请求参数 |
@ApiImplicitParam的属性:
属性 | 取值 | 作用 |
---|---|---|
paramType | 查询参数类型 | |
path | 以地址的形式提交数据 | |
query | 直接跟参数完成自动映射赋值(地址栏拼接查询条件,用对象属性封装) | |
body | 以流的形式提交 仅支持POST(JSON串提交,用@Requestbody接收) | |
header | 参数在request headers 里边提交 | |
form | 以form表单的形式提交 仅支持POST | |
dataType | 参数的数据类型 只作为标志说明,并没有实际验证 | |
Long | ||
String | ||
name | 接收参数名 | |
value | 接收参数的意义描述 | |
required | 参数是否必填 | |
true | 必填 | |
false | 非必填 | |
defaultValue | 默认值 |
在xc-service-api工程下创建config.Swagger2Configuration类,启动项目,访问localhost:31001/swagger-ui.html即可开启测试
标签:rop not amp ring OLE 完成后 before chm enc
原文地址:https://www.cnblogs.com/luboyan2524/p/11788570.html