This blog includes added custom CSS styles to the main Blogger template to enable consistent formatting of content related to software development, source code illustrations, etc. This post provides an overview of most of the formatting styles unique to the blog and can provide insights for others needing similar formatting capabilities. It also serves as a test document to verify subsequent changes to the blog template do not break existing content over time.
All Header Formats Adjacent
Here are all header elements shown together for size comparison purposes.
This is an H1 Header
This is an H2 Header
This is an H3 Header
This is an H4 Header
Using the <code> Tag
This paragraph references the Java classes ClientRegistryRepository
and InMemoryClientRegistryRepository
to see how text formatted via the <code>
HTML tag can make non-prose strings easier to separate for the reader from text that should be parsed like normal sentence content.
Using the <code class='command'> Tag
This paragraph references example commands a user might need to type such as mvn package
or java -jar .target/dependsgui.jar
to illustrate how specific command examples can be formatted to visually jump out of prose paragraphs for easier readiability.
Using the <code class='filename'> Tag
This paragraph references example filenames that might be referenced in an example to highlight them as an object rather than a normal prose word. References might be made to the pom.xml
file or application.properties
file on disk. to illustrate how specific command examples can be formatted to visually jump out of prose paragraphs for easier readiability.
Here are the various link state styles - hover on them to get hover color:
www.google.com Visited never.visited.com Not VisitedUsing the prosequote Class with <blockquote>
Prose text can be formatted using <blockquote class='prosequote'>
. The resulting text will be indented and the text will render in the primary proportional font on a light gray background as shown here.
The unanimous Declaration of the thirteen united States of America, When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.
Using the codequote Class with <blockquote>
Source code examples can be formatted using <blockquote class='codequote'>
then using <pre>
within the <blockquote>
element. The resulting text will be indented and the text will render in a monospace font on a light gray background as shown here.
@GetMapping("/public/privacypolicy") public String privacypolicyPage(Model model) { thisLog.info("executing privacypolicyPage()"); model.addAttribute("filename","c:/docs/policy/PrivacyPolicy.docx"); model.addAttribute("version","2022-04-30-version5"); return "public/privacypolicy.html"; }
Formatting Glossary Listings
Glossaries of terms can be formatted using HTML table elements with the <table class='glossarytable'>
, <td class='glossaryterm'>
and <td class='glossarydefinition'>
tags to achieve this visual layout on the screen.
BLUE | indicates classes used to implement OAuth2 functions in traditional servlets using ServletContext and HttpRequest / HttpResponse | GREEN | indicates classes used to implement OAuth2 functions in Reactive based components using WebExchageServer context | RED | indicates classes which have been deprecated for use as of Spring Security 5.7 and should NOT be used in any scenarios for maximum future-proof capabilities |
Formatting Caution Notes
Caution notes with a bright yellow caution icon can be generated using a similar <table class='caution'>
and <td class='cautionicon'>
and <td class='cautiontext'>
as shown here
to achieve this visual layout on the screen.
Extreme care must be exercised when creating these commands and copying / pasting strings. Extra spaces before or after parameter names or values will trigger errors in the Authorization server. EVERY CHARACTER COUNTS.
![]() |
Extreme care must be exercised when creating these commands and copying / pasting strings. Extra spaces before or after parameter names or values will trigger errors in the Authorization server. EVERY CHARACTER COUNTS. |
Other icon images such as stop signs can be saved and made available and used as shown below.
![]() |
If you search the web looking for help and find references to classes in GREEN when your application is NOT Reactive, STOP IMMEDIATELY. If you find references to classs in BLUE when you are writing a Reactive application, STOP IMMEDIATELY. Mixing BLUE and GREEN classes will create compilation problems if you're lucky or bizarre start-up errors if you get past compile stage. Know your scenario and stick to the proper set of classes designed for your model (ServletContext or Reactive). |
H3 Header - Formatting Gray Heading Tables
The grayheadertable
and grayheader
class styles can be used to create tables with this visual format:
Scenario | Required Classes |
---|---|
Legacy ServletContext | SecurityFilterChain @EnableWebSecurity @EnableGlobalMethodSecurity AccessDeniedHandler OAuthAuthenticationFailureHandler BearerTokenAuthentication |
Reactive WebExchangeServer | SecurityWebFilterChain @EnableWebFluxSecurity @EnableReactiveMethodSecurity ServerAccessDeniedHandler BearerTokenAuthentication |
Formatting Ordered Lists via <ol>
A numbered bulleted list will be rendered as shown below using the styles in this CSS stylesheet:
- We are using the same client-id, client-secret and token-uri from the example in the prior section.
- This is an internal administered client so a password can be shared directly with the deployment administrator so this client can use
authorization-grant-type=password
instead ofauthorization-code
- Because the client will not use
authorization-code
, theauthorization-uri
parameter isn't used and does not have to be provided. - Because the client will not use
authorization-code
, theredirect-uri
parameter isn't used and does not have to be provided. - Keycloak was configured to return the user name as
preferred_username
so this provider will be configured foruser-name-attribute=preferred_username
to match.
Copying Source Text to the Clipboard
Source code examples contained within an element with a named id can be copied to the clipboard with a short JavaScript.
copyToClipboard(elementid) { const range = document.createRange(); range.selectNode(document.getElementById(elmentid)); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); document.execCommand("copy"); window.getSelection().removeAllRanges(); }
With that script available as a JavaScript include, a button can be placed next to a block of code needing this clipboard capability that calls the above script and passes the name of the HTML element housing the desired code. Here's what the above formatted text looks like in the source HTML:
copyToClipboard(elementid) { const range = document.createRange(); range.selectNode(document.getElementById(elmentid)); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); document.execCommand("copy"); window.getSelection().removeAllRanges(); }
Using <div class="scrollbox"> for Scrolling Long/Wide Source Listings
Creating posts with long source-code examples within is a double-edged sword. While readers may find it helpful to have the full source locally on the page to scan rather than beign pointed to a folder on Github, etc., a long listing can also distract from the continuity of thought describing what the code is doing. In general, any listing longer than probably 15-20 lines will lose many readers. Instead, source code examples can be placed within a <div> element using class="scrollbox"
to create a mini-window with horizontal and vertical scroll bars to limit on-screen size while still allowing local viewing of all of the source. Here is a typical tag:
<div class="scrollbox">
Here is what a lengthy source listing looks like in that division on screen.
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
try {
thisLog.debug("doFilter() - filtering request=" + httpServletRequest.getRequestURI());
String base64jwt = this.extractToken(httpServletRequest);
if (StringUtils.hasText(base64jwt)) {
// if we are this far, the OAuth2AuthenticationProcessingFilter has already verified
// the access_token is not expired and its signature matches the public key the
// OAuth Authorization Server exposes in its jwk_uri endpoint -- now, we need to
// split the token into .-delimited chunks then convert each part from base64
String jwtparts[] = base64jwt.split("\\.");
String jwtheader = new String( Base64.decodeBase64(jwtparts[0]),"UTF-8");
String jwtpayload = new String( Base64.decodeBase64(jwtparts[1]),"UTF-8");
// thisLog.debug("doFilter() - clear-text jwt=" + jwtheader + " " + jwtpayload);
// thisLog.debug("doFilter() - clear-text jwt=MASKEDFORBREVITY");
try {
Authentication internalAuthentication = extractAuthentication(jwtpayload);
SecurityContextHolder.getContext().setAuthentication(internalAuthentication);
}
catch (Exception theE) {
thisLog.error("doFilter() -- parsing jwt -- Exception=" +theE);
}
}
}
catch (Exception eje) {
thisLog.error("doFilter() -- Exception creating Authentication object for SecurityContext - " + eje.toString() );
((HttpServletResponse) servletResponse).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
// regardless of what was encountered above, call doFilter to the larger chain
filterChain.doFilter(servletRequest, servletResponse);
}