百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

consul微服务治理中心踩坑 微服务治理范畴

yuyutoo 2024-10-12 01:23 1 浏览 0 评论

以consul为微服务治理中心的微服务架构演示

方法论

1. 前端组件化(可视化工具)

2. 后端微服务化(分布式统一管控)

3. 迭代自动化(CI/CD)

4. 过程流水线化(DevOps)

5. 定义接口入/出参后,通过KV模拟数据即可实现前后端联调,再深入开发相关微服务

本工程完整演示了以consul为微服务治理中心的标准微服务架构各个基本模块功能,通过该项目能够完整了解微服务注册、发现、健康监测、负载均衡、全链路监控、配置中心、权限控制等。



consul集群部署说明

修改配置文件,存放目录为consul.d,后缀为.json,可以有多个配置文件,后面的属性覆盖前面的。

1.公共基础配置文件/etc/consul.d/base-config.json

{

"ports": {

"http": 8500,

"dns": 8600,

"serf_lan": 8301,

"serf_wan": 8302,

"server": 8300

}

}

2.server节点的ACL配置文件acl.json

{

"datacenter": "dc1",

"acl_datacenter": "dc1",

"acl_master_token": "6407e6d8-1696-4b98-826d-0ad9a5c93449",

"acl_default_policy": "deny",

"server": true,

"log_level": "DEBUG",

"bootstrap_expect": 3,

"client_addr": "0.0.0.0"

}

3.client节点的ACL配置文件acl.json

{

"datacenter": "dc1",

"acl_datacenter": "dc1",

"acl_master_token": "6407e6d8-1696-4b98-826d-0ad9a5c93449",

"acl_token": "dd2c1eb3-7698-efb1-d213-f84d40fb5970",

"acl_default_policy": "deny",

"server": false,

"log_level": "DEBUG",

"client_addr": "0.0.0.0"

}

备注:

1. 先启动server

2. 浏览器打开UI,用acl_master_token设置ACL

3. 创建一个新的ACL

4. 将token配置到client的ACL文件的acl_token

5. 逐步启动client

6. 这个acl_token就是java bootstrap.yml中的consul配置

以docker方式启动consul

1.启动主服务server1

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-server -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.233 -config-dir=/etc/consul.d -node=server1 -ui

2.启动主服务server2

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-server -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.237 -config-dir=/etc/consul.d -node=server2 -retry-join=172.16.15.233

3.启动主服务server3

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-server -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.232 -config-dir=/etc/consul.d -node=server3 -retry-join=172.16.15.233

4.启动客户端client1

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-client -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.230 -config-dir=/etc/consul.d -node=client1 -retry-join=172.16.15.233

5.启动客户端client2

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-client -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.231 -config-dir=/etc/consul.d -node=client2 -retry-join=172.16.15.233

微服务模块

Springcloud 接入consul

1. 基本依赖包

参考父工程的pom文件

2. 把Spring consul的配置存放到bootstrap.yml文件里,而不是application.yml里边

spring:

cloud:

consul:

host: 172.28.50.28

port: 8500

discovery:

register: true

prefer-ip-address: true

instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}

acl-token: dd2c1eb3-7698-efb1-d213-f84d40fb5970

config:

enabled: true

format: yaml

watch:

enabled: true

prefix: config

data-key: data

3. 网关服务,在spring注入的时候,要把需要引入的组件注入到主应用里边

//注册到consul的注入项

@EnableDiscoveryClient

//引入zuul进行网关路由配置的注入项

@EnableZuulProxy

@SpringBootApplication

4. 业务集成服务,该服务是实现复杂业务逻辑的主体服务,是直接对接网关的微服务,是发现和调用其他微服务的主体服务

//在主应用注入微服务发现注入项

@EnableFeignClients

//建立一系列的接口类,通过接口类实现对其他微服务的调用

5. 利用consul KV静态、动态管理配置,consul也是一个配置中心,通过KV管理配置属性

1. 在consul KV中配置key的前缀为config(和consul.config.prefix属性值一致),下级目录为微服务名称,用逗号隔开为不同环境,以consul.config.data-key属性结尾,例如:config/accumulation-api-gateway,dev/data作为微服务accumulation-api-gateway的开发环境配置文件

2. 如果是静态配置属性,静态配置只在微服务重启的时候才会从consul KV获取一次,例如:RabbitMQ的配置

3. 如果要动态获取配置属性,则必须编写配置属性bean,动态配置会在consul KV更新后自动同步到微服务的对应bean上,例如:Redis的配置

api网关微服务api-gateway

路由配置、链路监控配置存储到consul的key/value中,路由指向业务逻辑层

#健康监控配置

management:

health:

redis:

enabled: false

consul:

enabled: true

#feign配置

zuul:

routes:

four-operations:

path: /api/**

serviceId: accumulation-business-layer

ribbon:

ReadTimeout: 120000

ConnectTimeout: 300000

#链路跟踪sleuth & zipkin配置

spring:

zipkin:

base-url: http://172.28.43.90:9411

sleuth:

sampler:

percentage: 1.0

业务逻辑层微服务business-layer

该微服务实现全部业务输出接口,对输入数据进行必要的合法性检测,解决跨域调用问题等

1. 在controler层对需要检测的对象注入`@Valid`

@CrossOrigin

@RequestMapping(value = "/login",method = RequestMethod.POST)

@ApiOperation(value = "注册用户",notes = "注册一个用户到系统中")

@ResponseBody

public String login(@RequestBody @Valid RegisterVO user) throws IOException {

log.info("参数={}",user);

//该用户是否已经注册

String accessToken=iSso.login(user.getUsername(),user.getPassword());

log.info("accessToken={}",accessToken);

JSONObject result=new JSONObject();

result.put("code",1000);

result.put("email",user.getUsername());

result.put("accessToken",accessToken);

return result.toJSONString();

}

2. 需要检测的对象注解正则式、提示信息等

public class RegisterVO {

@NotBlank(message = "用户名不能为空")

@Pattern(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}#34;,message = "必须为邮箱地址")

private String username;

@NotBlank(message = "密码不能为空")

@Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}#34;,message = "密码必须为数字、字母混合")

@Length(min = 8,max = 16,message = "密码长度必须为8-16个字符")

private String password;

}

3. 调用文件上传微服务,在接口中要指定consumes为MediaType.MULTIPART_FORM_DATA_VALUE,参数注解为@RequestPart,否则调用出错

@FeignClient(name = "accumulation-distribution-file-layer")

@RequestMapping("/file")

public interface IDistributionFile {

@PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)

String save(@RequestPart(value = "fileName") MultipartFile file);

@RequestMapping(value = "/download/{fileName}", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)

byte[] get(@PathVariable("fileName") String fileName);

}

缓存微服务层cache-layer

通过jedis实现对redis集群的使用

1. 在主类Application添加配置注解,解决autowire注入失败问题

//解决autowire注入失败问题

@EnableConfigurationProperties({RedisConfig.class})

2. redis配置从consul key/value动态获取,通过RedisConfig实例化redis连接池单例bean

#redis配置

redis:

host: 172.28.19.200

port: 7389

password:

timeout: 100

maxActive: 200

maxIdle: 200

minIdle: 5

maxWaitMillis: 10240

expireSeconds: 36000

commandTimeout: 10240

clusterNodes:

数据库持久层database-layer

该模块通过mybatis、mongodb演示了mysql关系型数据库及mongodb文档型数据库的使用方法

1. 数据库连接配置

#数据库连接

spring:

datasource:

driver-class-name: com.mysql.jdbc.Driver

url: jdbc:mysql://172.28.5.92:3306/ToonBeacon?useUnicode=true&characterEncoding=utf8

username: syswin

password: syswin

maxActive: 2335

maxIdel: 120

maxWait: 100

#mongodb配置

data:

mongodb:

uri: mongodb://172.28.43.18:27017/crazyicelee

2. 通过注解实现mysql数据库的VO映射,直接将sql注入到相关接口类中

@Mapper

public interface StudentDao {

@Results({

@Result(property = "name", column = "name"),

@Result(property = "age", column = "age"),

@Result(property = "sex", column = "sex"),

@Result(property = "email",column = "email")

})

@Select("SELECT * FROM student WHERE age > #{age}")

List<Student> searchAge(int age);

@Insert("INSERT INTO student(name, age,sex,email) VALUES (#{name}, #{age},#{sex},#{email})")

void addStudent(Student user);

@Update("UPDATE student SET name=#{name},sex=#{sex},age=#{age} WHERE email=#{email}")

void updateStudent(Student student);

@Delete("DELETE FROM student WHERE email=#{email}")

void deleteStudent(String email);

}

3. mongdb直接扩展MongoRepository作为接口实现数据库的访问

@Service

public interface UserRepository extends MongoRepository<User,String> {

}

4. 利用MongoDB 的GridFS分布式存储文件

4.1 创建GridFS的GridFSBucket bean

@Configuration

public class MongoConf {

@Autowired

private MongoDbFactory mongoDbFactory;

@Bean

public GridFSBucket getGridFSBuckets() {

MongoDatabase db = mongoDbFactory.getDb();

return GridFSBuckets.create(db);

}

}

4.2 实现文件上传、下载、删除API

@RestController

@RequestMapping("/file")

public class GridFSController {

private static Logger LOGGER = LoggerFactory.getLogger(GridFSController.class);

@Autowired

private GridFsTemplate gridFsTemplate;

@Autowired

private GridFSBucket gridFSBucket;

@PostMapping(value = "/upload")

public String save(@RequestParam(value = "fileName") MultipartFile file) {

LOGGER.info("Saving file..");

DBObject metaData = new BasicDBObject();

metaData.put("createdDate", new Date());

String fileName = UUID.randomUUID().toString();

try {

InputStream inputStream = file.getInputStream();

gridFsTemplate.store(inputStream, fileName, file.getContentType(), metaData);

} catch (IOException e) {

LOGGER.error("IOException: " + e);

throw new RuntimeException("System Exception while handling request");

}

LOGGER.info("File return: " + fileName);

return fileName;

}

@RequestMapping(value = "/download", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)

public byte[] get(@RequestParam(value = "fileName") String fileName) throws IOException {

LOGGER.info("Getting file.." + fileName);

GridFSFile result = gridFsTemplate.findOne(new Query().addCriteria(Criteria.where("filename").is(fileName)));

if (result == null) {

LOGGER.info("File not found" + fileName);

throw new RuntimeException("No file with name: " + fileName);

}

LOGGER.info("File found " + fileName);

//打开流下载对象

GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(result.getObjectId());

//获取流对象

GridFsResource gridFsResource=new GridFsResource(result,downloadStream);

return IOUtils.toByteArray(gridFsResource.getInputStream());

}

@RequestMapping(value = "/delete", method = RequestMethod.DELETE)

public void delete(@RequestParam(value = "fileName") String fileName) {

LOGGER.info("Deleting file.." + fileName);

gridFsTemplate.delete(new Query().addCriteria(Criteria.where("filename").is(fileName)));

LOGGER.info("File deleted " + fileName);

}

}

消息队列接入层message-layer

本模块实现了接入rabbitmq的消息发送、接收,通过注解方式实现

#RabbitMq配置

spring:

rabbitmq:

host: 172.28.19.123

port: 5672

username: guest

password: guest

virtual-host: /

publisher-confirms: true

单点登录微服务层sso-layer

本模块以JWT演示了用户登录token的实现,可以将token存储到redis进行全站认证

1. 基于OAuth2框架实现SSO

用mysql作为用户体系数据存储系统,mybatis作为数据库连接器,以SQL注解到DAO接口的方式实现简单的数据库访问。

1.1 在启动主类添加Mapper扫码注解,指定数据库映射类所在包,并且要注解@EnableWebSecurity,标明该服务提供OAuth2认证

@SpringBootApplication

@EnableAuthorizationServer

@EnableWebSecurity

@MapperScan(basePackages = "com.crazyice.lee.accumulation.sso.dao")

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

1.2 SQL注解到接口实现数据库访问

这里特别说明SQL的IN操作实现方法,该接口必须添加@Mapper、@Repository注解,否则可能导致@Autowired失效或者创建Bean失败

@Mapper

@Repository

public interface SysPermissionServiceDao {

@Results({

@Result(property = "id", column = "id"),

@Result(property = "pid", column = "pid"),

@Result(property = "type", column = "type"),

@Result(property = "name",column = "name"),

@Result(property = "code",column = "code"),

@Result(property = "uri",column = "uri"),

@Result(property = "seq",column = "seq"),

@Result(property = "createUser",column = "create_user"),

@Result(property = "createTime",column = "create_time"),

@Result(property = "updateUser",column = "update_user"),

@Result(property = "updateTime",column = "update_time")

})

@Select({"<script>"+

"SELECT * FROM sys_permission WHERE id IN "+

"<foreach collection='ids' item='id' open='(' separator=',' close=')'>"+

"#{id}"+

"</foreach>"+

"</script>"

})

List<SysPermission> findByIds(@Param("ids") List<Integer> ids);

}

1.3 实现WebSecurityConfigurerAdapter适配器

@Configuration

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired

private DemoUserDetailsService demoUserDetailsService;

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

auth.userDetailsService(demoUserDetailsService).passwordEncoder(passwordEncoder());

}

@Override

public void configure(WebSecurity web) throws Exception {

web.ignoring().antMatchers("/assets/**", "/css/**", "/images/**");

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.formLogin()

.loginPage("/login")

.and()

.authorizeRequests()

.antMatchers("/login").permitAll()

.anyRequest()

.authenticated()

.and().csrf().disable().cors();

}

@Bean

public PasswordEncoder passwordEncoder() {

return new SCryptPasswordEncoder();

}

}

1.4 实现UserDetailsService接口

@Service

public class DemoUserDetailsService implements UserDetailsService {

private static final Logger LOGGER = LoggerFactory.getLogger(DemoUserDetailsService.class);

private static final PasswordEncoder passwordEncoder=new SCryptPasswordEncoder();

@Autowired

private SysUserServiceDao sysUserServiceDao;

@Autowired

private PermissionService permissionService;

@Override

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

//根据用户名从数据库获取用户信息

SysUser sysUser = sysUserServiceDao.getByUsername(username);

if (null == sysUser) {

LOGGER.warn("用户:{},不存在", username);

throw new UsernameNotFoundException(username);

}

//根据用户id获取用户权限

List<SysPermission> permissionList = permissionService.findByUserId(sysUser.getId());

List<SimpleGrantedAuthority> authorityList = new ArrayList<>();

permissionList.stream().forEach(item->authorityList.add(new SimpleGrantedAuthority(item.getCode())));

//生成用户信息进行口令验证

User user = new User(sysUser.getUsername(), passwordEncoder.encode(sysUser.getPassword()), authorityList);

LOGGER.info("登录用户: {}", JSON.toJSONString(user));

return user;

}

}

2. 实现OAuth2认证服务

自定义springboot注解演示模块myself-annotation

本模块以aop的方式实现了自定义注解的演示

websocket服务演示模块

本模块以websocket演示了websocket协议的服务端及客户端,实现了服务端的连接监听、消息监听、消息发送、不在线用户推送通知等,客户端实现了新用户加入、退出、和指定人聊天、群发等。


1. 其他bean注入websocket方法

websocket的ServerEndpoint不能直接使用@Autowired将其他bean注入进来,而应该使用以下步骤

1.1 在主程序Application中使用静态方法调用传递参数,代码如下:

public class Application {

public static void main(String[] args) {

SpringApplication springApplication = new SpringApplication(Application.class);

ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);

//解决WebSocket不能注入的问题

WebSocketServer.setApplicationContext(configurableApplicationContext);

}

@Bean

public ServerEndpointExporter serverEndpointExporter(){

return new ServerEndpointExporter();

}

}

1.2 在websocket程序中定义需要注入的bean,代码如下:

//此处是解决无法注入的关键

private static ApplicationContext applicationContext;

//注入的service

private static ISendNotice iSendNotice;

//注入动态配置

private static ThirdParam thirdParam;

//注入本地缓存service

private static CacheServer cacheServer;

1.3 在websocket程序中定义set方法接纳参数,代码如下:

//外部bean注入进来

public static void setApplicationContext(ApplicationContext applicationContext) {

WebSocketServer.applicationContext = applicationContext;

WebSocketServer.iSendNotice=applicationContext.getBean(ISendNotice.class);

WebSocketServer.thirdParam=applicationContext.getBean(ThirdParam.class);

WebSocketServer.cacheServer=applicationContext.getBean(CacheServer.class);

}

2. 利用ehcache将用户信息持久化缓存到本地

2.1 配置ehcache.xml,将eternal="true"

2.2 配置缓存策略服务CacheServer并注入进websocket中使用,cache key为字符串的时候要用单引号'括住

超级账本fabric链代码演示模块

该模块实现了运行在超级账本区块链上的链码编写,接入,相关接口对接等功能演示

快速数据字典查询服务

该模块以极简的方式实现了通用数据自典查询服务,利用consul KV的自动同步特性为分布式数据字典维护和查询提供了极简的解决方案。

1. 将数据字典以KV的方式配置到consul平台


2. 给数据字典配置动态bean,该bean动态从consul KV获取数据字典的MAP数据,存储到内存中,所以在提供给微服务查询时速度很快,解决了通常处理方案的读取数据库、加载缓存等中间过程,既保证了数据一致性,又保证了分布式服务的高可靠及内存访问的高效率。

@ConfigurationProperties(prefix = "dictionary")

@Data

public class DictionaryConfig {

private Map sex;

private Map province;

private Map city;

}

备注:每添加一个字典,只需要在该代码里边增加一个Map属性即可

3. 通用的restFul API,该服务通过反射机制实现了一致的数据字典查询,适用所有基于MAP数据格式的数据字典,而且可以根据Key的前缀进行级联过滤。

@RestController

public class Controller {

private static Logger log = LoggerFactory.getLogger(Controller.class);

@Autowired

private DictionaryConfig dictionaryConfig;

//首字母转大写

public static String toUpperCaseFirstOne(String s){

if(Character.isUpperCase(s.charAt(0)))

return s;

else

return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();

}

@RequestMapping(value = "/getDictionary/{name}",method = RequestMethod.GET)

@ApiOperation(value = "字典",notes = "获取指定字典的KV列表")

@ApiImplicitParams({

@ApiImplicitParam(paramType = "query",name="filter",value = "删选key",dataType = "String")

})

public Map getDictionary(@PathVariable("name") String name, @RequestParam(value = "filter",name = "filter",required = false) String filter){

try {

Map<String,String> totalMap=(Map) dictionaryConfig.getClass().getMethod("get" + toUpperCaseFirstOne(name)).invoke(dictionaryConfig);

if(filter==null) {

return totalMap;

}

else{

return totalMap.entrySet().stream().filter((e)->{

if(e.getKey().startsWith(filter))

return true;

else

return false;

}).collect(Collectors.toMap((e)->e.getKey(),(e)->e.getValue()));

}

} catch (IllegalAccessException e) {

log.error(e.getLocalizedMessage());

} catch (InvocationTargetException e) {

log.error(e.getLocalizedMessage());

} catch (NoSuchMethodException e) {

log.error(e.getLocalizedMessage());

}

return null;

}

}

个性化驾驶舱

该微服务以KV的方式提供个性化驾驶舱数据并配合前端联调,通过这种模式能够加速接口定义及联调效率。

1. 驾驶舱按照用户个性化标识动态提供需要显示的模块数据,前端根据模块数据及类型以相关样式显示这些模块

2. 通过配置consul的key/value来调整数据配合前端用户交互,确定接口数据结构后就可以深入开发相关模块的后端逻辑

3. 每个模块的数据为统一的list对象,再深入的数据结构可以根据模块的实际情况自由定义,该数据映射为bean Model

##################

# 以下配置到consul #

##################

#健康监控配置

management:

health:

redis:

enabled: false

consul:

enabled: true

#个性化模块列表

personal:

cockpits:

- userId: 13701231472

models:

- 1

- 3

- 4

- 5

- userId: 13691491904

models:

- 1

- 2

- 3

- 4

- 5

- userId: 18513125518

models:

- 3

- 4

- 5

#个性化模块内容

models:

- id: 1

type: visit

name: 会议管理

data:

- name: 调查内容一

- name: 调查内容二

- id: 2

type: list

name: 调查信息

data:

- name: 调查内容一

- name: 调查内容二

- id: 3

type: content

name: 内容展示

data:

- name: 丰富的可视化类型 ECharts 提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。

- id: 4

type: app

name: 应用

data:

- name: 会议

visit: 122

img: http://scloud.toon.mobi/f/oCu-gQmNjNhDXnXOy8qPI8gPXQOM9kCn6mSLoRdYI+IfG.png

- name: 日程

visit: 122

img: http://scloud.toon.mobi/f/Mzu1uXTPFTo1mZaqY195QCdMGFhJRm47VPaPGVrB8d8fG.png

- name: 问卷调查

visit: 122

img: http://scloud.toon.mobi/f/VPTW828DPVYWOQEC6rgx-uThn2PRffr9OoRoR+Yk0WgfG.png

- id: 5

type: chart-loudou

name: 漏斗图

data:

- name: 访问

value: 20

- name: 资讯

value: 40

- name: 订单

value: 60

- name: 点击

value: 80

- name: 展示

value: 100

- id: 6

type: chart-zhexian

name: 一周信息统计

data:

- name: 访问

value: 12

- name: 资讯

value: 19

- name: 订单

value: 12

- name: 点击

value: 15

- name: 展示

value: 18

本工程的完整源代码

该工程代码经过验证均可正常运行。

[码云git下载地址](https://gitee.com/crazyicelee/accumulation.git)

相关推荐

MySQL5.5+配置主从同步并结合ThinkPHP5设置分布式数据库

前言:本文章是在同处局域网内的两台windows电脑,且MySQL是5.5以上版本下进行的一主多从同步配置,并且使用的是集成环境工具PHPStudy为例。最后就是ThinkPHP5的分布式的连接,读写...

thinkphp5多语言怎么切换(thinkphp5.1视频教程)

thinkphp5多语言进行切换的步骤:第一步,在配置文件中开启多语言配置。第二步,创建多语言目录。相关推荐:《ThinkPHP教程》第三步,编写语言包。视图代码:控制器代码:效果如下:以上就是thi...

基于 ThinkPHP5 + Bootstrap 的后台开发框架 FastAdmin

FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架。主要特性基于Auth验证的权限管理系统支持无限级父子级权限继承,父级的管理员可任意增删改子级管理员及权限设置支持单...

Thinkphp5.0 框架实现控制器向视图view赋值及视图view取值操作示

本文实例讲述了Thinkphp5.0框架实现控制器向视图view赋值及视图view取值操作。分享给大家供大家参考,具体如下:Thinkphp5.0控制器向视图view的赋值方式一(使用fetch()方...

thinkphp5实现简单评论回复功能(php评论回复功能源码下载)

由于之前写评论回复都是使用第三方插件:畅言所以也就没什么动手,现在证号在开发一个小的项目,所以就自己动手写评论回复,没写过还真不知道评论回复功能听着简单,但仔细研究起来却无法自拔,由于用户量少,所以...

ThinkPHP框架——实现定时任务,定时更新、清理数据

大家好,我是小蜗牛,今天给大家分享一下,如何用ThinkPHP5.1.*版本实现定时任务,例如凌晨12点更新数据、每隔10秒检测过期会员、每隔几分钟发送请求保证ip的活性等本次分享,主要用到一个名为E...

BeyongCms系统基于ThinkPHP5.1框架的轻量级内容管理系统

BeyongCms内容管理系统(简称BeyongCms)BeyongCms系统基于ThinkPHP5.1框架的轻量级内容管理系统,适用于企业Cms,个人站长等,针对移动App、小程序优化;提供完善简...

YimaoAdminv3企业建站系统,使用 thinkphp5.1.27 + mysql 开发

介绍YimaoAdminv3.0.0企业建站系统,使用thinkphp5.1.27+mysql开发。php要求5.6以上版本,推荐使用5.6,7.0,7.1,扩展(curl,...

ThinkAdmin-V5开发笔记(thinkpad做开发)

前言为了快速开发一款小程序管理后台,在众多的php开源后台中,最终选择了基于thinkphp5的,轻量级的thinkadmin系统,进行二次开发。该系统支持php7。文档地址ThinkAdmin-V5...

thinkphp5.0.9预处理导致的sql注入复现与详细分析

复现先搭建thinkphp5.0.9环境...

thinkphp5出现500错误怎么办(thinkphp页面错误)

thinkphp5出现500错误,如下图所示:相关推荐:《ThinkPHP教程》require():open_basedirrestrictionineffect.File(/home/ww...

Thinkphp5.0极速搭建restful风格接口层

下面是基于ThinkPHPV5.0RC4框架,以restful风格完成的新闻查询(get)、新闻增加(post)、新闻修改(put)、新闻删除(delete)等server接口层。1、下载Thin...

基于ThinkPHP5.1.34 LTS开发的快速开发框架DolphinPHP

DophinPHP(海豚PHP)是一个基于ThinkPHP5.1.34LTS开发的一套开源PHP快速开发框架,DophinPHP秉承极简、极速、极致的开发理念,为开发集成了基于数据-角色的权限管理机...

ThinkPHP5.*远程代码执行高危漏洞手工与升级修复解决方法

漏洞描述由于ThinkPHP5框架对控制器名没有进行足够的安全检测,导致在没有开启强制路由的情况下,黑客构造特定的请求,可直接GetWebShell。漏洞评级严重影响版本ThinkPHP5.0系列...

Thinkphp5代码执行学习(thinkphp 教程)

Thinkphp5代码执行学习缓存类RCE版本5.0.0<=ThinkPHP5<=5.0.10Tp框架搭建环境搭建测试payload...

取消回复欢迎 发表评论: