基于javaweb+mysql的ssm+maven药店信息管理系统(java+ssm+jsp+layui+maven+mysql)

基于javaweb+mysql的ssm+maven药店信息管理系统(java+ssm+jsp+layui+maven+mysql)

私信源码获取及调试交流

运行环境

Java≥8、MySQL≥5.7、Tomcat≥8

开发工具

eclipse/idea/myeclipse/sts等均可配置运行

适用

课程设计,大作业,毕业设计,项目练习,学习演示等

功能说明

基于javaweb的SSM+Maven药店信息管理系统(java+ssm+jsp+layui+maven+mysql)

一、项目简述 环境配置:

Jdk1.8 + Tomcat8.5 + mysql + Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)

项目技术:

JSP +Spring + SpringMVC + MyBatis + html+ css + JavaScript + JQuery + Ajax + layui+ maven等等

			return false;
		}

		SecurityExpressionHandler<FilterInvocation> handler = getExpressionHandler();

		Expression accessExpression;
		try {
			accessExpression = handler.getExpressionParser().parseExpression(getAccess());

		}
		catch (ParseException e) {
			IOException ioException = new IOException();
			ioException.initCause(e);
			throw ioException;
		}

		return ExpressionUtils.evaluateAsBoolean(accessExpression,
				createExpressionEvaluationContext(handler));
	}

	/**
	 * Allows the {@code EvaluationContext} to be customized for variable lookup etc.
	 */
	protected EvaluationContext createExpressionEvaluationContext(
			SecurityExpressionHandler<FilterInvocation> handler) {
		FilterInvocation f = new FilterInvocation(getRequest(), getResponse(),
				new FilterChain() {
					public void doFilter(ServletRequest request, ServletResponse response)
							throws IOException, ServletException {
						throw new UnsupportedOperationException();
					}
				});

		return handler.createEvaluationContext(SecurityContextHolder.getContext()
				.getAuthentication(), f);
	}

	/**
	 * Make an authorization decision based on the URL and HTTP method attributes. True is
	 * returned if the user is allowed to access the given URL as defined.
	 *
	 * @return the result of the authorization decision
	 * @throws IOException
	 */
	public boolean authorizeUsingUrlCheck() throws IOException {
		String contextPath = ((HttpServletRequest) getRequest()).getContextPath();
		Authentication currentUser = SecurityContextHolder.getContext()
				.getAuthentication();
		return getPrivilegeEvaluator().isAllowed(contextPath, getUrl(), getMethod(),
				currentUser);
	}

/**
 * Spring Security配置类
 * @E-mail suzeping10@126.com
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)/* 启用全局方法权限控制,prePostEnabled = true 表示开启一些注解的使用 */
@EnableWebSecurity/* 启用web环境下权限控制功能 */
public class WebApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
	// 修改DelegatingFilterProxy的源码
	// 使SpringMVC[dispatcherServlet]把WebApplicationSecurityConfig扫描到IOC容器
	// 才可以针对浏览器请求进行权限控制
	// 而并非是Spring[contextLoaderListener]扫描WebApplicationSecurityConfig

	@Autowired
	private UserDetailsService userDetailsService;

	@Autowired
	private BCryptPasswordEncoder passwordEncoder;

	/**
	 * 拦截服务器请求
	 * @param security
	 * @throws Exception
	 */
	@Override
	protected void configure(HttpSecurity security) throws Exception {
		security.authorizeRequests()// 对请求进行授权
				.antMatchers("/admin/to/login/page.html")// 首页
				.permitAll()// 无条件访问
				.antMatchers("/static/**")// 静态资源
				.permitAll()// 无条件访问
				.antMatchers("/admin/get/page.html")
				.access("hasRole('用户管理员') or hasRole('超级管理员')")
@EnableGlobalMethodSecurity(prePostEnabled = true)/* 启用全局方法权限控制,prePostEnabled = true 表示开启一些注解的使用 */
@EnableWebSecurity/* 启用web环境下权限控制功能 */
public class WebApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
	// 修改DelegatingFilterProxy的源码
	// 使SpringMVC[dispatcherServlet]把WebApplicationSecurityConfig扫描到IOC容器
	// 才可以针对浏览器请求进行权限控制
	// 而并非是Spring[contextLoaderListener]扫描WebApplicationSecurityConfig

	@Autowired
	private UserDetailsService userDetailsService;

	@Autowired
	private BCryptPasswordEncoder passwordEncoder;

	/**
	 * 拦截服务器请求
	 * @param security
	 * @throws Exception
	 */
	@Override
	protected void configure(HttpSecurity security) throws Exception {
		security.authorizeRequests()// 对请求进行授权
				.antMatchers("/admin/to/login/page.html")// 首页
				.permitAll()// 无条件访问
				.antMatchers("/static/**")// 静态资源
				.permitAll()// 无条件访问
				.antMatchers("/admin/get/page.html")
				.access("hasRole('用户管理员') or hasRole('超级管理员')")
				.antMatchers("/role/get/page.html")
				.access("hasRole('角色管理员') or hasRole('超级管理员')")
				.antMatchers("/medicine/get/tree.html")
				.access("hasRole('药品管理员') or hasRole('超级管理员')")
				.antMatchers("/instrument/get/tree.html")
				.access("hasRole('器械管理员') or hasRole('超级管理员')")
				.antMatchers("/sell/get/tree.html")
				.access("hasRole('店员') or hasRole('超级管理员')")
				.antMatchers("/check/get/tree.html")
				.access("hasRole('医师') or hasRole('超级管理员')")
				.anyRequest()// 任意请求
				.authenticated()// 认证后访问
	 * 拦截服务器请求
	 * @param security
	 * @throws Exception
	 */
	@Override
	protected void configure(HttpSecurity security) throws Exception {
		security.authorizeRequests()// 对请求进行授权
				.antMatchers("/admin/to/login/page.html")// 首页
				.permitAll()// 无条件访问
				.antMatchers("/static/**")// 静态资源
				.permitAll()// 无条件访问
				.antMatchers("/admin/get/page.html")
				.access("hasRole('用户管理员') or hasRole('超级管理员')")
				.antMatchers("/role/get/page.html")
				.access("hasRole('角色管理员') or hasRole('超级管理员')")
				.antMatchers("/medicine/get/tree.html")
				.access("hasRole('药品管理员') or hasRole('超级管理员')")
				.antMatchers("/instrument/get/tree.html")
				.access("hasRole('器械管理员') or hasRole('超级管理员')")
				.antMatchers("/sell/get/tree.html")
				.access("hasRole('店员') or hasRole('超级管理员')")
				.antMatchers("/check/get/tree.html")
				.access("hasRole('医师') or hasRole('超级管理员')")
				.anyRequest()// 任意请求
				.authenticated()// 认证后访问
				.and()
				.exceptionHandling()
				.accessDeniedHandler(new AccessDeniedHandler() {
					@Override
					public void handle(HttpServletRequest request, HttpServletResponse response,
									   AccessDeniedException accessDeniedException) throws IOException, ServletException {
						request.setAttribute("exception", new Exception(DrugConstant.MESSAGE_ACCESS_DENIED));
						request.getRequestDispatcher("/WEB-INF/views/system-error.jsp").forward(request, response);
					}
				})
				.and()
				.csrf()
				.disable()// 禁用csrf
				.formLogin()// 表单登录
				.loginPage("/admin/to/login/page.html")// 指定登陆页面
				.loginProcessingUrl("/security/do/login.html")// 指定处理登录的地址
				.defaultSuccessUrl("/admin/to/main/page.html",true)// 指定登陆成功去往的地址
				.usernameParameter("account")// 账号的请求参数name
				.passwordParameter("password")// 密码的请求参数name
				.and()
				.logout()
				.logoutUrl("/security/do/logout.html")// 指定处理注销的地址
				.logoutSuccessUrl("/admin/to/login/page.html");// 注销成功去往的页面
	}

	/**
	 * 登陆验证
	 * @param auth

/**
 * 异常处理器
 * @E-mail suzeping10@126.com
 */
@ControllerAdvice
public class DrugExceptionResolver {

	/**
	 * 修改时用户名重复异常处理
	 * @param exception
	 * @param request
	 * @param response
	 * @return
	 * @throws IOException
	 */
	@ExceptionHandler(AccountEditDuplicateKeyException.class)
	public ModelAndView resolveAccountEditDuplicateKeyException(AccountEditDuplicateKeyException exception, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String viewName = "system-error";
		return commonResolve(viewName, exception, request, response);
	}

	/**
	 * 新增时用户名重复异常处理
	 * @param exception
	 * @param request
	 * @param response
	 * @return
	 * @throws IOException
	 */
	@ExceptionHandler(AccountAddDuplicateKeyException.class)
	public ModelAndView resolveAccountAddDuplicateKeyException(AccountAddDuplicateKeyException exception, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String viewName = "admin-add";
		return commonResolve(viewName, exception, request, response);
	}

	/**
	 * 未登录就访问被保护资源异常处理
	 * @param exception
	 * @param request
	 * @param response
	 * @return
	 * @throws IOException
	 */
	@ExceptionHandler(Exception.class)
	public ModelAndView resolveException(Exception exception, HttpServletRequest request, HttpServletResponse response)
		return roleService.getPageInfo(keyword, pageNum, pageSize);
	}

	/**
	 * 新增role(并返回新增后总数量)
	 * @param role
	 * @return
	 */
	@PostMapping("/save.json")
	public ResultEntity<Integer> saveRole(DrugRole role){
		return roleService.saveRole(role);
	}

	/**
	 * 修改role
	 * @param role
	 * @return
	 */
	@PostMapping("/edit.json")
	public ResultEntity<String> editRole(DrugRole role){
		return roleService.editRole(role);
	}

	/**
	 * 批量删除role[通过roleId数据进行删除]
	 * @param roleIds
	 * @return
	 */
	@PostMapping("/del.json")
	public ResultEntity<String> removeRole(@RequestBody List<String> roleIds){
		return roleService.removeRole(roleIds);
	}
}

/**
 * 工具类
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("exception",exception);
		modelAndView.setViewName(viewName);
		return modelAndView;
	}
}

/**
 * 管理员前端控制器
 * @E-mail suzeping10@126.com
 */
@Slf4j
@Controller
@RequestMapping("/admin")
public class DrugAdminController {

	@Autowired
	private DrugAdminService adminService;

	/**
	 * 分页获取管理员列表(含关键词搜索)
	 * @param keyword
	 * @param pageNum
	 * @param pageSize
	 * @param map
	 * @return
	 */
	@GetMapping("/get/page.html")
	}

	/**
	 * Make an authorization decision based on a Spring EL expression. See the
	 * "Expression-Based Access Control" chapter in Spring Security for details on what
	 * expressions can be used.
	 *
	 * @return the result of the authorization decision
	 * @throws IOException
	 */
	public boolean authorizeUsingAccessExpression() throws IOException {
		if (SecurityContextHolder.getContext().getAuthentication() == null) {
			return false;
		}

		SecurityExpressionHandler<FilterInvocation> handler = getExpressionHandler();

		Expression accessExpression;
		try {
			accessExpression = handler.getExpressionParser().parseExpression(getAccess());

		}
		catch (ParseException e) {
			IOException ioException = new IOException();
			ioException.initCause(e);
			throw ioException;
		}

		return ExpressionUtils.evaluateAsBoolean(accessExpression,
				createExpressionEvaluationContext(handler));
	}

	/**
	 * Allows the {@code EvaluationContext} to be customized for variable lookup etc.
	 */
	protected EvaluationContext createExpressionEvaluationContext(
			SecurityExpressionHandler<FilterInvocation> handler) {
		FilterInvocation f = new FilterInvocation(getRequest(), getResponse(),
				new FilterChain() {
					public void doFilter(ServletRequest request, ServletResponse response)
							throws IOException, ServletException {
						throw new UnsupportedOperationException();
		return checkService.removeCheck(checkId);
	}
}

/**
 * 角色前端控制器
 * @E-mail suzeping10@126.com
 */
@Slf4j
@RestController
@RequestMapping("/role")
public class DrugRoleController {

	@Autowired
	private DrugRoleService roleService;

	/**
	 * 分页获取role
	 * @param keyword
	 * @param pageNum
	 * @param pageSize
	 * @return
	 */
	@PostMapping("/get/page.json")
	public ResultEntity<PageInfo<DrugRole>> getPageInfo(
			@RequestParam(value = "keyword",defaultValue = "") String keyword,
			@RequestParam(value = "pageNum",defaultValue = "1") String pageNum,
			@RequestParam(value = "pageSize",defaultValue = "5") String pageSize
	){
		return roleService.getPageInfo(keyword, pageNum, pageSize);
	}

	/**
	 * 新增role(并返回新增后总数量)
	 * @param role
	 * @return
	 */
	@PostMapping("/save.json")
	 * This method allows subclasses to provide a way to access the ServletContext
	 * according to the rendering technology.
	 */
	protected abstract ServletContext getServletContext();

	/**
	 * Make an authorization decision by considering all &lt;authorize&gt; tag attributes.
	 * The following are valid combinations of attributes:
	 * <ul>
	 * <li>access</li>
	 * <li>url, method</li>
	 * </ul>
	 * The above combinations are mutually exclusive and evaluated in the given order.
	 *
	 * @return the result of the authorization decision
	 * @throws IOException
	 */
	public boolean authorize() throws IOException {
		boolean isAuthorized;

		if (StringUtils.hasText(getAccess())) {
			isAuthorized = authorizeUsingAccessExpression();

		}
		else if (StringUtils.hasText(getUrl())) {
			isAuthorized = authorizeUsingUrlCheck();

		}
		else {
			isAuthorized = false;

		}

		return isAuthorized;
	}

	/**
	 * Make an authorization decision based on a Spring EL expression. See the
	 * "Expression-Based Access Control" chapter in Spring Security for details on what
	 * expressions can be used.
	 *
	 * @return the result of the authorization decision
	 * @throws IOException
	 */
	public boolean authorizeUsingAccessExpression() throws IOException {
		if (SecurityContextHolder.getContext().getAuthentication() == null) {
			return false;
		}

		SecurityExpressionHandler<FilterInvocation> handler = getExpressionHandler();

		Expression accessExpression;
	 * @param response
	 * @return
	 * @throws IOException
	 */
	@ExceptionHandler(AccountEditDuplicateKeyException.class)
	public ModelAndView resolveAccountEditDuplicateKeyException(AccountEditDuplicateKeyException exception, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String viewName = "system-error";
		return commonResolve(viewName, exception, request, response);
	}

	/**
	 * 新增时用户名重复异常处理
	 * @param exception
	 * @param request
	 * @param response
	 * @return
	 * @throws IOException
	 */
	@ExceptionHandler(AccountAddDuplicateKeyException.class)
	public ModelAndView resolveAccountAddDuplicateKeyException(AccountAddDuplicateKeyException exception, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String viewName = "admin-add";
		return commonResolve(viewName, exception, request, response);
	}

	/**
	 * 未登录就访问被保护资源异常处理
	 * @param exception
	 * @param request
	 * @param response
	 * @return
	 * @throws IOException
	 */
	@ExceptionHandler(Exception.class)
	public ModelAndView resolveException(Exception exception, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String viewName = "system-error";
		return commonResolve(viewName, exception, request, response);
	}

	public ResultEntity<Map<String,Object>> saveSell(DrugSell sell){
		return sellService.saveSell(sell);
	}

	/**
	 * 删除记录
	 * @param sellId
	 * @return
	 */
	@PostMapping("/del.json")
	public ResultEntity<String> removeSell(@RequestParam("sellId") String sellId){
		return sellService.removeSell(sellId);
	}
}

/**
 * 药品前端控制器
 * @E-mail suzeping10@126.com
 */
@Slf4j
@RestController
@RequestMapping("/medicine")
public class DrugMedicineController {

	@Autowired
	private DrugMedicineService medicineService;

	/**
	 * 分页获取药品
	 * @param medicineName
	 * @param medicineType
	 * @param pageNum
	 * @param pageSize
	 * @return
	 */
	@PostMapping("/get/page.json")
	public ResultEntity<PageInfo<DrugMedicine>> getPageInfo(
			@RequestParam(value = "medicineName",defaultValue = "") String medicineName,
			@RequestParam(value = "medicineType",defaultValue = "") String medicineType,
			@RequestParam(value = "pageNum",defaultValue = "1") String pageNum,

/**
 * 售出记录前端控制器
 * @E-mail suzeping10@126.com
 */
@Slf4j
@RestController
@RequestMapping("/sell")
public class DrugSellController {

	@Autowired
	private DrugSellService sellService;

	/**
	 * 获取全部在售药品及器械
	 * @return
	 */
	@GetMapping("/getAllOther.json")
	public ResultEntity<List<Map<String,Object>>> getAllOther(){
		return sellService.getAllOther();
	}

	/**
	 * 获取药品或器械的单价
	 * @return
	 */
	@PostMapping("/getOtherPrice.json")
	public ResultEntity<String> getOtherPrice(String otherId){
		return sellService.getOtherPrice(otherId);
	}

	/**
	 * 分页获取售出记录
	 * @param sellName
	 * @param otherName
	 * @param pageNum
	 * @param pageSize
	 * @return
	 */
	@PostMapping("/get/page.json")
	public ResultEntity<PageInfo<DrugSellPage>> getPageInfo(
			@RequestParam(value = "sellName",defaultValue = "") String sellName,
			@RequestParam(value = "otherName",defaultValue = "") String otherName,
			@RequestParam(value = "pageNum",defaultValue = "1") String pageNum,
			@RequestParam(value = "pageSize",defaultValue = "5") String pageSize
	){
		return sellService.getPageInfo(sellName, otherName, pageNum, pageSize);
	}

		adminService.saveAssignAdminRole(adminId,roleIdList);
		return "redirect:/admin/get/page.html?pageNum=" + pageNum + "&keyword=" + keyword;
	}
}

/**
 * 体检前端控制器
 * @E-mail suzeping10@126.com
 */
@Slf4j
@RestController
@RequestMapping("/check")
public class DrugCheckController {

	@Autowired
	private DrugCheckService checkService;

	/**
	 * 分页获取体检记录
	 * @param checkName
	 * @param pageNum
	 * @param pageSize
	 * @return
	 */
	@PostMapping("/get/page.json")
	public ResultEntity<PageInfo<DrugCheck>> getPageInfo(
			@RequestParam(value = "checkName",defaultValue = "") String checkName,
			@RequestParam(value = "pageNum",defaultValue = "1") String pageNum,
			@RequestParam(value = "pageSize",defaultValue = "5") String pageSize
	){
 * @E-mail suzeping10@126.com
 */
@Slf4j
@RestController
@RequestMapping("/medicine")
public class DrugMedicineController {

	@Autowired
	private DrugMedicineService medicineService;

	/**
	 * 分页获取药品
	 * @param medicineName
	 * @param medicineType
	 * @param pageNum
	 * @param pageSize
	 * @return
	 */
	@PostMapping("/get/page.json")
	public ResultEntity<PageInfo<DrugMedicine>> getPageInfo(
			@RequestParam(value = "medicineName",defaultValue = "") String medicineName,
			@RequestParam(value = "medicineType",defaultValue = "") String medicineType,
			@RequestParam(value = "pageNum",defaultValue = "1") String pageNum,
			@RequestParam(value = "pageSize",defaultValue = "5") String pageSize
	){
		return medicineService.getPageInfo(medicineName, medicineType, pageNum, pageSize);
	}

	/**
	 * 新增药品(并返回新增后总数量)
	 * @param medicine
	 * @return
	 */
	@PostMapping("/save.json")
	public ResultEntity<Integer> saveMedicine(DrugMedicine medicine){
		return medicineService.saveMedicine(medicine);
	}

	/**
	 * 修改药品
	 * @param medicine
	 * @return
	 */
	@PostMapping("/edit.json")
	public ResultEntity<String> editMedicine(DrugMedicine medicine){
		return medicineService.editMedicine(medicine);
	}

	/**
	 * 删除药品

/**
 * 角色前端控制器
 * @E-mail suzeping10@126.com
 */
@Slf4j
@RestController
@RequestMapping("/role")
public class DrugRoleController {

	@Autowired
	private DrugRoleService roleService;

	/**
	 * 分页获取role
	 * @param keyword
	 * @param pageNum
	 * @param pageSize
	 * @return
	 */
	@PostMapping("/get/page.json")
	public ResultEntity<PageInfo<DrugRole>> getPageInfo(
			@RequestParam(value = "keyword",defaultValue = "") String keyword,
			@RequestParam(value = "pageNum",defaultValue = "1") String pageNum,
			@RequestParam(value = "pageSize",defaultValue = "5") String pageSize
	){
		return roleService.getPageInfo(keyword, pageNum, pageSize);
	}

	/**
	 * 新增role(并返回新增后总数量)
	 * @param role
	 * @return
	 */
	@PostMapping("/save.json")
	public ResultEntity<Integer> saveRole(DrugRole role){
}

/**
 * 异常处理器
 * @E-mail suzeping10@126.com
 */
@ControllerAdvice
public class DrugExceptionResolver {

	/**
	 * 修改时用户名重复异常处理
	 * @param exception
	 * @param request
	 * @param response
	 * @return
	 * @throws IOException
	 */
	@ExceptionHandler(AccountEditDuplicateKeyException.class)
	public ModelAndView resolveAccountEditDuplicateKeyException(AccountEditDuplicateKeyException exception, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String viewName = "system-error";
		return commonResolve(viewName, exception, request, response);
	}

	/**
	 * 新增时用户名重复异常处理
	 * @param exception
	 * @param request
	 * @param response
	/*------------- Private helper methods  -----------------*/

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private SecurityExpressionHandler<FilterInvocation> getExpressionHandler()
			throws IOException {
//		ApplicationContext appContext = SecurityWebApplicationContextUtils.findRequiredWebApplicationContext(getServletContext());
		ServletContext sc = getServletContext();
		String attrName = FrameworkServlet.SERVLET_CONTEXT_PREFIX + "dispatcherServlet";
		ApplicationContext appContext = (ApplicationContext) sc.getAttribute(attrName);
		Map<String, SecurityExpressionHandler> handlers = appContext
				.getBeansOfType(SecurityExpressionHandler.class);

		for (SecurityExpressionHandler h : handlers.values()) {
			if (FilterInvocation.class.equals(GenericTypeResolver.resolveTypeArgument(
					h.getClass(), SecurityExpressionHandler.class))) {
				return h;
			}
		}

		throw new IOException(
				"No visible WebSecurityExpressionHandler instance could be found in the application "
						+ "context. There must be at least one in order to support expressions in JSP 'authorize' tags.");
	}

	private WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() throws IOException {
		WebInvocationPrivilegeEvaluator privEvaluatorFromRequest = (WebInvocationPrivilegeEvaluator) getRequest()
				.getAttribute(WebAttributes.WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE);
		if (privEvaluatorFromRequest != null) {
			return privEvaluatorFromRequest;
		}

		ApplicationContext ctx = SecurityWebApplicationContextUtils.findRequiredWebApplicationContext(getServletContext());
		Map<String, WebInvocationPrivilegeEvaluator> wipes = ctx
				.getBeansOfType(WebInvocationPrivilegeEvaluator.class);

		if (wipes.size() == 0) {
			throw new IOException(
					"No visible WebInvocationPrivilegeEvaluator instance could be found in the application "
							+ "context. There must be at least one in order to support the use of URL access checks in 'authorize' tags.");
		}

		return (WebInvocationPrivilegeEvaluator) wipes.values().toArray()[0];

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值